P5056 插头dp
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的更多相关文章
- P5056 【模板】插头dp
\(\color{#0066ff}{ 题目描述 }\) 给出n*m的方格,有些格子不能铺线,其它格子必须铺,形成一个闭合回路.问有多少种铺法? \(\color{#0066ff}{输入格式}\) 第1 ...
- [学习笔记]插头dp
基于连通性的状压dp 巧妙之处:插头已经可以表示内部所有状态了. 就是讨论麻烦一些. 简介 转移方法:逐格转移,分类讨论 记录状态方法:最小表示法(每次要重新编号,对于一类没用“回路路径”之类的题,可 ...
- 插头dp小结
插头dp: \(A:\)插头dp是什么? \(B:\)一种基于连通性状态压缩的动态规划问题 \(A:\)请问有什么应用呢? \(B:\)各种网格覆盖问题,范围允许状压解决,常用于计算方案数与联通块权值 ...
- 插头 dp
插头dp 洛谷 黑题板子? P5056 给出n×m的方格,有些格子不能铺线,其它格子必须铺,形成一个闭合回路.问有多少种铺法? 1.轮廓线 简单地说,轮廓线就是已决策格子和未决策格子的分界线: 2,插 ...
- P5056-[模板]插头dp
正题 题目链接:https://www.luogu.com.cn/problem/P5056 题目大意 \(n*m\)的网格,求有多少条回路可以铺满整个棋盘. 解题思路 插头\(dp\)的,写法是按照 ...
- 插头dp
插头dp 感受: 我觉得重点是理解,算法并不是直接想出怎样由一种方案变成另一种方案.而是方案本来就在那里,我们只是枚举状态统计了答案. 看看cdq的讲义什么的,一开始可能觉得状态很多,但其实灰常简单 ...
- HDU 4113 Construct the Great Wall(插头dp)
好久没做插头dp的样子,一开始以为这题是插头,状压,插头,状压,插头,状压,插头,状压,无限对又错. 昨天看到的这题. 百度之后发现没有人发题解,hust也没,hdu也没discuss...在acm- ...
- HDU 4949 Light(插头dp、位运算)
比赛的时候没看题,赛后看题觉得比赛看到应该可以敲的,敲了之后发现还真就会卡题.. 因为写完之后,无限TLE... 直到后来用位运算代替了我插头dp常用的decode.encode.shift三个函数以 ...
- 插头DP专题
建议入门的人先看cd琦的<基于连通性状态压缩的动态规划问题>.事半功倍. 插头DP其实是比较久以前听说的一个东西,当初是水了几道水题,最近打算温习一下,顺便看下能否入门之类. 插头DP建议 ...
随机推荐
- 【洛谷P1083】[NOIP2012]借教室
借教室 [题目描述] 在n天中每天有一个可以借出的教室数,有m个订单,每个订单从第l天到第r天要借用x个教室.问能否满足所有的订单,若不能,输出第一个不能满足的订单编号. 思路: 1.1 ≤ n,m ...
- eclipse 安装/卸载插件
1.通过Help>>Install New Soft 之后弹出对话框,可以通过“Add”按钮添加已经有的插件的(zip等)或者输入安装地址,之后按照要求即可.2.对于安装失败的插件,再次进 ...
- redis的事务、主从复制、持久化
redis事务 和其它数据库一样,Redis作为NoSQL数据库也同样提供了事务机制.在Redis中, MULTI/EXEC/DISCARD/WATCH这四个命令是我们实现事务的基石.Redis中事务 ...
- 第12章 GPIO输出—使用固件库点亮LED
本章参考资料:<STM32F76xxx参考手册>.库帮助文档<STM32F779xx_User_Manual.chm>. 利用库建立好的工程模板,就可以方便地使用STM32 H ...
- postman发送HTTP请求自动生成MD5签名
POSTMAN是常用的接口测试工具 如何进行MD5签名呢? 代码如下: /** * 通过request.data获取body的内容,这个是postman内置变量 * 常用内置参数如下: * reque ...
- JS JavaScript中的this
this是JavaScript语言中的一个关键字 它是函数运行时,在函数体内部自动生成的一个对象,只能在函数体内部使用. function test() { this.x = 1; } 上面代码中,函 ...
- oracle https://localhost:1158/em 无法打开
解决办法一: 首先查看本机Oracle安装路径中 portlist.ini 文件里面的端口号是多少,例如我的就是5500. 那么在浏览器中输入的地址就是:https://localhost:5500/ ...
- jwplayer 参数记录
jwplayer().getPosition()://播放了多少秒 jwplayer('playerdiv').play(); || jwplayer(0).play(true/false); // ...
- docker安装MySQL 8.0及初始化错误处理
Preface Several days ago,I've implement a docker environmnet,I'm gonna Install a MySQL 8. ...
- nginx: [error] open() "/var/run/nginx.pid" failed (2: No such file or directory)
解决办法: nginx nginx -s reload