题面

Source:

unordered_map:

#include <iostream>
#include <tr1/unordered_map>
#include <cstdio>
#include <cstring> using namespace std; const int maxM = 200005; #define LL long long char mp[20][20];
int c[4] = {0, -1, 1, 0};
int n, m, ex, ey;
tr1::unordered_map<int, LL> Ht[2], T; int now;
int set(int state, int x, int val) //使状态的第x位变成val
{ x <<= 1; return (state & (~(3<<x))) | (val << x); }
int get(int state, int x) //得到转态的第x位
{ x <<= 1; return (state >> x) & 3; }
int getl(int state, int x) //得到与x所配对的左括号的位置
{ int cnt = 1, l = x; while (cnt) cnt += c[get(state, --l)]; return l; }
int getr(int state, int x) //得到与x所匹配的右括号的位置
{ int cnt = -1, r = x; while (cnt) cnt += c[get(state, ++r)]; return r; } void update(int x, int y, int state, LL val) {//状态转移(分类讨论), 刷表法
int p = get(state, y), q = get(state, y + 1);
if (mp[x][y] == '*') {//如果是障碍
if (p == 0 && q == 0) Ht[now ^ 1][state] += val;//特判
return;
} if (p == 0 && q == 0) {//如果没有插头
if (x == n - 1 || y == m - 1) return;
int newst = set(state, y, 1);
newst = set(newst, y + 1, 2);
Ht[now ^ 1][newst] += val;
return;
} if (p == 0 || q == 0) {//如果只有一端有插头,则往右或往下插
if (y < m - 1) {//往下插
int newst = set(state, y, 0);
newst = set(newst, y + 1, p + q);
Ht[now ^ 1][newst] += val;
}
if (x < n - 1) {//往右插
int newst = set(state, y, p + q);
newst = set(newst, y + 1, 0);
Ht[now ^ 1][newst] += val;
}
return;
} int newst = set(state, y, 0); newst = set(newst, y + 1, 0); if (p == 1 && q == 1) //如果两个插头同为左括号,连起来后y+1对应的右插头要变成左插头
newst = set(newst, getr(state, y + 1), 1);
else if (p == 2 && q == 2) //如果两个插头同为右括号,连起来后y对应的左插头要变成右插头
newst = set(newst, getl(state, y), 2);
else if (p == 1 && q == 2 && (x != ex || y != ey)) return;//只有最后一个格子才能转移 Ht[now ^ 1][newst] += val;
} int main() {
#ifndef ONLINE_JUDGE
freopen("BZOJ1814.in", "r", stdin);
#endif
cin >> n >> m;
for (int i = 0; i < n; ++ i) cin >> mp[i];
for (int i = 0; i < n; ++ i)
for (int j = 0; j < m; ++ j)
if (mp[i][j] == '.') ex = i, ey = j;
now = 0;
Ht[now].clear();
Ht[now][0] = 1;//别忘了
for (int i = 0; i < n; ++ i) {
//下面一部分是转移到下一行时的key<<=2
T.clear();
for (tr1::unordered_map<int, LL>::iterator it = Ht[now].begin(); it != Ht[now].end(); ++ it)
T[it->first<<2] = it->second;
swap(T, Ht[now]); for (int j = 0; j < m; ++ j) {
Ht[now ^ 1].clear();//记得转移之前清除
for (tr1::unordered_map<int, LL>::iterator it = Ht[now].begin(); it != Ht[now].end(); ++ it)
update(i, j, it->first, it->second);
now ^= 1;
}
}
cout << Ht[now][0] << endl;//最后的轮廓线状态就是0
}

手码Hash_Table:

#include <iostream>
#include <cstdio>
#include <cstring> using namespace std; const int maxM = 200005; #define LL long long char mp[20][20];
int c[4] = {0, -1, 1, 0};
int n, m, ex, ey; struct Hash_List {
struct Node {
int key, nxt;
LL val;
} data[maxM];
int head[maxM], cnt;
void init() { cnt = 0; memset(head, 0, sizeof head); }
void insert(int key, LL val) {
int x = key % maxM;
for (int i = head[x]; i; i = data[i].nxt)
if (data[i].key == key) {
data[i].val += val;
return;
}
data[++cnt] = (Node) { key, head[x], val };
head[x] = cnt;
}
LL getval(int key) {
int x = key % maxM;
for (int i = head[x]; i; i = data[i].nxt) {
if (data[i].key == key) {
return data[i].val;
}
}
return 0;
}
}DP[2]; int now;
int set(int state, int x, int val)
{ x <<= 1; return (state & (~(3<<x))) | (val << x); }
int get(int state, int x)
{ x <<= 1; return (state >> x) & 3; }
int getl(int state, int x)
{ int cnt = 1, l = x; while (cnt) cnt += c[get(state, --l)]; return l; }
int getr(int state, int x)
{ int cnt = -1, r = x; while (cnt) cnt += c[get(state, ++r)]; return r; } void update(int x, int y, int state, LL val) {
int p = get(state, y), q = get(state, y + 1);
if (mp[x][y] == '*') {
if (p == 0 && q == 0) DP[now ^ 1].insert(state, val);
return;
} if (p == 0 && q == 0) {
if (x == n - 1 || y == m - 1) return;
int newst = set(state, y, 1);
newst = set(newst, y + 1, 2);
DP[now ^ 1].insert(newst, val);
return;
} if (p == 0 || q == 0) {
if (y < m - 1) {
int newst = set(state, y, 0);
newst = set(newst, y + 1, p + q);
DP[now ^ 1].insert(newst, val);
}
if (x < n - 1) {
int newst = set(state, y, p + q);
newst = set(newst, y + 1, 0);
DP[now ^ 1].insert(newst, val);
}
return;
} int newst = set(state, y, 0); newst = set(newst, y + 1, 0); if (p == 1 && q == 1)
newst = set(newst, getr(state, y + 1), 1);
if (p == 2 && q == 2)
newst = set(newst, getl(state, y), 2);
if (p == 1 && q == 2 && (x != ex || y != ey)) return; DP[now ^ 1].insert(newst, val);
} int main() {
#ifndef ONLINE_JUDGE
freopen("BZOJ1814.in", "r", stdin);
#endif
cin >> n >> m;
for (int i = 0; i < n; ++ i) cin >> mp[i];
for (int i = 0; i < n; ++ i)
for (int j = 0; j < m; ++ j)
if (mp[i][j] == '.') ex = i, ey = j;
now = 0;
DP[now].init(); DP[now].insert(0, 1);
for (int i = 0; i < n; ++ i) {
for (int j = 1; j <= DP[now].cnt; ++ j) DP[now].data[j].key <<= 2;
for (int j = 0; j < m; ++ j) {
DP[now ^ 1].init();
for (int k = 1; k <= DP[now].cnt; ++ k)
update(i, j, DP[now].data[k].key, DP[now].data[k].val);
now ^= 1;
}
}
cout << DP[now].getval(0) << endl;
}

P5056 插头dp的更多相关文章

  1. P5056 【模板】插头dp

    \(\color{#0066ff}{ 题目描述 }\) 给出n*m的方格,有些格子不能铺线,其它格子必须铺,形成一个闭合回路.问有多少种铺法? \(\color{#0066ff}{输入格式}\) 第1 ...

  2. [学习笔记]插头dp

    基于连通性的状压dp 巧妙之处:插头已经可以表示内部所有状态了. 就是讨论麻烦一些. 简介 转移方法:逐格转移,分类讨论 记录状态方法:最小表示法(每次要重新编号,对于一类没用“回路路径”之类的题,可 ...

  3. 插头dp小结

    插头dp: \(A:\)插头dp是什么? \(B:\)一种基于连通性状态压缩的动态规划问题 \(A:\)请问有什么应用呢? \(B:\)各种网格覆盖问题,范围允许状压解决,常用于计算方案数与联通块权值 ...

  4. 插头 dp

    插头dp 洛谷 黑题板子? P5056 给出n×m的方格,有些格子不能铺线,其它格子必须铺,形成一个闭合回路.问有多少种铺法? 1.轮廓线 简单地说,轮廓线就是已决策格子和未决策格子的分界线: 2,插 ...

  5. P5056-[模板]插头dp

    正题 题目链接:https://www.luogu.com.cn/problem/P5056 题目大意 \(n*m\)的网格,求有多少条回路可以铺满整个棋盘. 解题思路 插头\(dp\)的,写法是按照 ...

  6. 插头dp

    插头dp 感受: 我觉得重点是理解,算法并不是直接想出怎样由一种方案变成另一种方案.而是方案本来就在那里,我们只是枚举状态统计了答案. 看看cdq的讲义什么的,一开始可能觉得状态很多,但其实灰常简单 ...

  7. HDU 4113 Construct the Great Wall(插头dp)

    好久没做插头dp的样子,一开始以为这题是插头,状压,插头,状压,插头,状压,插头,状压,无限对又错. 昨天看到的这题. 百度之后发现没有人发题解,hust也没,hdu也没discuss...在acm- ...

  8. HDU 4949 Light(插头dp、位运算)

    比赛的时候没看题,赛后看题觉得比赛看到应该可以敲的,敲了之后发现还真就会卡题.. 因为写完之后,无限TLE... 直到后来用位运算代替了我插头dp常用的decode.encode.shift三个函数以 ...

  9. 插头DP专题

    建议入门的人先看cd琦的<基于连通性状态压缩的动态规划问题>.事半功倍. 插头DP其实是比较久以前听说的一个东西,当初是水了几道水题,最近打算温习一下,顺便看下能否入门之类. 插头DP建议 ...

随机推荐

  1. Android学习笔记_73_授权过程

    .需要申请App Key和App Secret.不同的开发平台有不同的接入方式,可以参考文档,然后将这两个值放进去. .通过OAuth类实现认证,它会自动跳转到认证界面,进行授权,成功之后需要处理回调 ...

  2. 旧文备份:硬盘MBR引导记录损坏的一种修复方法

    硬盘MBR信息损坏原因:硬盘上安装了windows XP和linux双系统,在windows下安装一套软件,破解的时候修改了硬盘的序列号,结果导致引导系统的grub无法完成linux的引导,只能进到w ...

  3. OCiOS开发:CAGradientLayer 渐变色

    OCiOS开发:CAGradientLayer 渐变色 CAGradientLayer 简介 CAGradientLayer是CALayer图层类的子类,用于处理渐变色的层结构. CAGradient ...

  4. SAP销售订单屏幕字段控制隐藏,必输等

    1.T-CODE:shd0 创建变式  , 点击确认按钮后,SAP进入下一个屏幕,然后重复上面的操作,直到所有屏幕已完成设置. 如果后续屏幕不需要设置,可点击“退出并保存”按钮.保存后,进入下图所示页 ...

  5. javascript--自定义弹出登陆窗口(弹出窗)

    web开发中浏览器对象封装了诸如prompt.alert.confirm等弹出框,但是有的弹出框并不能满足开发需要,需要我们自己定义弹出框,诸如用户登陆框.消息提示框等.本文利用弹出用户登陆框示例,对 ...

  6. 微信小程序 - 生命周期 - 参数传递

    ​ 现在WEB开发门槛越来越高,不想java 会了就可以有工作,前端不行 ,不仅JavaScript要求不低,基础的HTML+CSS还要扎实,jquery也是必须要会,现在的前端框架 Vue Ng R ...

  7. cors(Cross-origin resource sharing)跨域资源共享

    阮一峰老师的文章(http://www.ruanyifeng.com/blog/2016/04/cors.html)跨域资源共享详解和https://developer.mozilla.org/zh- ...

  8. 【PHP】PHP常用数组(Array)函数整理

    整理了一份PHP开发中数组操作大全,包含有数组操作的基本函数.数组的分段和填充.数组与栈.数组与列队.回调函数.排序.计算.其他的数组函数等. 一.数组操作的基本函数 数组的键名和值 array_va ...

  9. mysql在cmd里中文乱码解决办法

    右边画红线部分中文已经乱码,左边红线里中文则完美显示出来了. 解决办法   用set  names   utf-8: 效果如图

  10. stata操作

    //stata操作 *************************数据基本操作****************************** gen varname = value //定义变量 r ...