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建议 ...
随机推荐
- Android学习笔记_73_授权过程
.需要申请App Key和App Secret.不同的开发平台有不同的接入方式,可以参考文档,然后将这两个值放进去. .通过OAuth类实现认证,它会自动跳转到认证界面,进行授权,成功之后需要处理回调 ...
- 旧文备份:硬盘MBR引导记录损坏的一种修复方法
硬盘MBR信息损坏原因:硬盘上安装了windows XP和linux双系统,在windows下安装一套软件,破解的时候修改了硬盘的序列号,结果导致引导系统的grub无法完成linux的引导,只能进到w ...
- OCiOS开发:CAGradientLayer 渐变色
OCiOS开发:CAGradientLayer 渐变色 CAGradientLayer 简介 CAGradientLayer是CALayer图层类的子类,用于处理渐变色的层结构. CAGradient ...
- SAP销售订单屏幕字段控制隐藏,必输等
1.T-CODE:shd0 创建变式 , 点击确认按钮后,SAP进入下一个屏幕,然后重复上面的操作,直到所有屏幕已完成设置. 如果后续屏幕不需要设置,可点击“退出并保存”按钮.保存后,进入下图所示页 ...
- javascript--自定义弹出登陆窗口(弹出窗)
web开发中浏览器对象封装了诸如prompt.alert.confirm等弹出框,但是有的弹出框并不能满足开发需要,需要我们自己定义弹出框,诸如用户登陆框.消息提示框等.本文利用弹出用户登陆框示例,对 ...
- 微信小程序 - 生命周期 - 参数传递
现在WEB开发门槛越来越高,不想java 会了就可以有工作,前端不行 ,不仅JavaScript要求不低,基础的HTML+CSS还要扎实,jquery也是必须要会,现在的前端框架 Vue Ng R ...
- cors(Cross-origin resource sharing)跨域资源共享
阮一峰老师的文章(http://www.ruanyifeng.com/blog/2016/04/cors.html)跨域资源共享详解和https://developer.mozilla.org/zh- ...
- 【PHP】PHP常用数组(Array)函数整理
整理了一份PHP开发中数组操作大全,包含有数组操作的基本函数.数组的分段和填充.数组与栈.数组与列队.回调函数.排序.计算.其他的数组函数等. 一.数组操作的基本函数 数组的键名和值 array_va ...
- mysql在cmd里中文乱码解决办法
右边画红线部分中文已经乱码,左边红线里中文则完美显示出来了. 解决办法 用set names utf-8: 效果如图
- stata操作
//stata操作 *************************数据基本操作****************************** gen varname = value //定义变量 r ...