插头DP题目泛做(为了对应WYD的课件)
题目1:BZOJ 1814 URAL 1519 Formula 1
题目大意:给定一个N*M的棋盘,上面有障碍格子。求一个经过所有非障碍格子形成的回路的数量。
插头DP入门题。记录连通分量。
#include <bits/stdc++.h> using namespace std; const int maxd = ;
const int hash = ;
const int State = ;
typedef long long ll; ll ans = ;
int n, m;
int maze[maxd][maxd];
int code[maxd], ch[maxd];
int end_x, end_y;
char str[maxd]; struct HashMap {
int head[hash], next[State], size;
ll state[State], f[State]; void Init() {
size = ;
memset(head, -, sizeof head);
} void push(ll st, ll ans) {
int h = st % hash; for(int i = head[h]; i != -; i = next[i]) {
if(state[i] == st) {
f[i] += ans;
return;
}
}
state[size] = st;
f[size] = ans;
next[size] = head[h];
head[h] = size ++;
}
}dp[]; void decode(int *code, int s, ll st) {
for(int i = s; i >= ; -- i) {
code[i] = st & ;
st >>= ;
}
} ll encode(int *code, int s) {
int cnt = ;
ll st = ; memset(ch, -, sizeof ch);
ch[] = ;
for(int i = ; i <= s; ++ i) {
if(ch[code[i]] == -) ch[code[i]] = cnt ++;
code[i] = ch[code[i]];
st <<= ;
st |= code[i];
}
return st;
} void Shit(int *code, int s) {
for(int i = s; i >= ; -- i)
code[i] = code[i - ];
code[] = ;
} void dpblank(int x, int y, int cur) {
int left, up; for(int i = ; i < dp[cur].size; ++ i) {
decode(code, m, dp[cur].state[i]);
left = code[y - ];
up = code[y]; if(left && up) {
if(left == up) {
if(x == end_x && y == end_y) {
code[y - ] = code[y] = ;
if(y == m) Shit(code, m);
dp[cur ^ ].push(encode(code, m), dp[cur].f[i]);
}
}
else {
code[y - ] = code[y] = ;
for(int j = ; j <= m; ++ j)
if(code[j] == up)
code[j] = left;
if(y == m) Shit(code, m);
dp[cur ^ ].push(encode(code, m), dp[cur].f[i]);
}
}
else if((left && !up) || (!left && up)) {
int t; if(left) t = left;
else t = up;
if(maze[x][y + ]){
code[y - ] = ;
code[y] = t;
dp[cur ^ ].push(encode(code, m), dp[cur].f[i]);
}
if(maze[x + ][y]) {
code[y - ] = t;
code[y] = ;
if(y == m) Shit(code, m);
dp[cur ^ ].push(encode(code, m), dp[cur].f[i]);
}
}
else {
if(maze[x][y + ] && maze[x + ][y]) {
code[y - ] = code[y] = ;
dp[cur ^ ].push(encode(code, m), dp[cur].f[i]);
}
}
}
} void dpblock(int x, int y, int cur) {
for(int i = ; i < dp[cur].size; ++ i) {
decode(code, m, dp[cur].state[i]);
code[y - ] = code[y] = ;
if(y == m) Shit(code, m);
dp[cur ^ ].push(encode(code, m), dp[cur].f[i]);
}
} void Input() {
memset(maze, , sizeof maze); scanf("%d%d", &n, &m);
for(int i = ; i <= n; ++ i) {
scanf("%s", str + );
for(int j = ; j <= m; ++ j) {
if(str[j] == '.') {
maze[i][j] = ;
end_x = i; end_y = j;
}
}
}
} void Solve() {
int cur = ;
ans = ; dp[cur].Init();
dp[cur].push(, );
for(int i = ; i <= n; ++ i) {
for(int j = ; j <= m; ++ j) {
dp[cur ^ ].Init();
if(maze[i][j]) dpblank(i, j, cur);
else dpblock(i, j, cur);
cur ^= ;
}
} for(int i = ; i < dp[cur].size; ++ i) {
ans += dp[cur].f[i];
} } void Output() {
printf("%lld\n", ans);
} int main(){
Input();
Solve();
Output(); return ;
}
BZOJ 1814
题目2:HDU 1693
求障碍棋盘上面多回路数。
因为求多回路,所以不一定在最后一个非障碍格子形成回路。只要当前状态相邻的两个格子有下插头和右插头,就是一个新的回路。所以对于此时的插头来说,我们可以不记插头所在的连通分量,只记录其是否存在即可。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath> using namespace std; const int maxd = ;
const int Hash = ;
const int State = ;
typedef long long ll; ll ans = ;
int n, m;
int maze[maxd][maxd];
int code[maxd]; struct HashMap {
int head[Hash], next[State], size;
ll state[State], f[State]; void Init() {
size = ;
memset(head, -, sizeof head);
} void push(ll st, ll ans) {
int h = st % Hash; for(int i = head[h]; i != -; i = next[i]) {
if(state[i] == st) {
f[i] += ans;
return;
}
} f[size] = ans;
state[size] = st;
next[size] = head[h];
head[h] = size ++;
}
}dp[]; void opencode(int *code, int s, ll st) {
for(int i = s; i >= ; -- i) {
code[i] = st & ;
st >>= ;
}
} ll lockcode(int *code, int s) {
ll st = ; for(int i = ; i <= s; ++ i) {
st <<= ;
st |= code[i];
} return st;
} void Shit(int *code, int s) {
for(int i = s; i >= ; -- i) {
code[i] = code[i - ];
}
code[] = ;
} void dpblank(int x, int y, int cur) {
int left, up; for(int i = ; i < dp[cur].size; ++ i) {
opencode(code, m, dp[cur].state[i]);
left = code[y - ];
up = code[y];
if(left && up) {
code[y - ] = code[y] = ;
if(y == m) Shit(code, m);
dp[cur ^ ].push(lockcode(code, m), dp[cur].f[i]);
}
else if(left || up) {
if(maze[x][y + ]) {
code[y - ] = ;
code[y] = ;
dp[cur ^ ].push(lockcode(code, m), dp[cur].f[i]);
}
if(maze[x + ][y]) {
code[y - ] = ;
code[y] = ;
if(y == m) Shit(code, m);
dp[cur ^ ].push(lockcode(code, m), dp[cur].f[i]);
}
}
else {
if(maze[x + ][y] && maze[x][y + ]) {
code[y - ] = code[y] = ;
dp[cur ^ ].push(lockcode(code, m), dp[cur].f[i]);
}
}
}
} void dpblock(int x, int y, int cur) {
for(int i = ; i < dp[cur].size; ++ i) {
opencode(code, m, dp[cur].state[i]);
code[y - ] = code[y] = ;
if(y == m) Shit(code, m);
dp[cur ^ ].push(lockcode(code, m), dp[cur].f[i]);
}
} void Input() {
scanf("%d%d", &n, &m);
memset(maze, , sizeof maze);
for(int i = ; i <= n; ++ i) {
for(int j = ; j <= m; ++ j) {
scanf("%d", &maze[i][j]);
}
}
} void Solve() {
int cur = ; dp[cur].Init();
dp[cur].push(, );
for(int i = ; i <= n; ++ i) {
for(int j = ; j <= m; ++ j) {
dp[cur ^ ].Init();
if(maze[i][j]) dpblank(i, j, cur);
else dpblock(i, j, cur);
cur ^= ;
}
} ans = ;
for(int i = ; i < dp[cur].size; ++ i) {
ans += dp[cur].f[i];
}
} void Output() {
printf("There are %lld ways to eat the trees.\n", ans);
} int main() {
int t, cnt = ; scanf("%d", &t); while(t --) {
++ cnt;
printf("Case %d: ", cnt);
Input();
Solve();
Output();
} return ;
}
HDU 1693
题目3: BZOJ 1210 HNOI 2004 邮递员
求一个棋盘上面从(1,1)到(N,N)有多少不同的路径。经过所有格子。
只要求一个回路。然后答案*2就可以了。要用高精度,不想打了,于是就Spj了一个极端数据。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <algorithm> using namespace std; const int maxd = ;
const int State = ;
const int Hash = ;
typedef long long ll; int n, m;
ll Out_ans = ;
int code[maxd], ch[maxd]; struct HashMap {
int head[Hash], next[State], size;
ll f[State], state[State]; void Init() {
size = ;
memset(head, -, sizeof head);
} void push(ll st, ll ans) {
int h = st % Hash; for(int i = head[h]; i != -; i = next[i]) {
if(state[i] == st) {
f[i] += ans;
return;
}
} f[size] = ans;
state[size] = st;
next[size] = head[h];
head[h] = size ++;
}
}dp[]; void opencode(int *code, int s, ll st) {
for(int i = s; i >= ; -- i) {
code[i] = st & ;
st >>= ;
}
} ll lockcode(int *code, int s) {
int cnt = ;
ll st = ; memset(ch, -, sizeof ch);
ch[] = ;
for(int i = ; i <= s; ++ i) {
if(ch[code[i]] == -)
ch[code[i]] = cnt ++;
code[i] = ch[code[i]];
st <<= ;
st |= code[i];
} return st;
} void Shit(int *code, int s) {
for(int i = s; i >= ; -- i) {
code[i] = code[i - ];
}
code[] = ;
} void dpblank(int x, int y, int cur) {
int left, up; for(int i = ; i < dp[cur].size; ++ i) {
opencode(code, n, dp[cur].state[i]);
left = code[y - ];
up = code[y]; if(left && up) {
if(left == up) {
if(x == m && y == n) {
code[y - ] = ; code[y] = ;
if(y == n) Shit(code, n);
dp[cur ^ ].push(lockcode(code, n), dp[cur].f[i]);
}
}
else {
code[y - ] = code[y] = ;
for(int j = ; j <= n; ++ j)
if(code[j] == up)
code[j] = left;
if(y == n) Shit(code, n);
dp[cur ^ ].push(lockcode(code, n), dp[cur].f[i]);
}
}
else if(left || up) {
int t = ; if(left) t = left;
else t = up; if(x <= m && y + <= n) {
code[y - ] = ; code[y] = t;
dp[cur ^ ].push(lockcode(code, n), dp[cur].f[i]);
}
if(x + <= m && y <= n) {
code[y - ] = t; code[y] = ;
if(y == n) Shit(code, n);
dp[cur ^ ].push(lockcode(code, n), dp[cur].f[i]);
}
}
else {
if(x + <= m && y + <= n) {
code[y - ] = code[y] = ;
dp[cur ^ ].push(lockcode(code, n), dp[cur].f[i]);
}
}
}
} void Input() {
scanf("%d%d", &n, &m);
if(n == || m == ) {
puts("");
exit();
}
if(n == && m == ) {
puts(""); //不想写高精度
exit();
}
} void Solve() {
int cur = ; dp[cur].Init();
dp[cur].push(, );
for(int i = ; i <= m; ++ i) {
for(int j = ; j <= n; ++ j) {
dp[cur ^ ].Init();
dpblank(i, j, cur);
cur ^= ;
}
} for(int i = ; i < dp[cur].size; ++ i)
Out_ans += dp[cur].f[i];
} void Output() {
printf("%lld\n", Out_ans << );
} #define ONLINE_JUDGE
int main() {
#ifndef ONLINE_JUDGE
freopen("postman.in", "r", stdin);
freopen("postman.out", "w", stdout);
#endif Input();
Solve();
Output(); #ifndef ONLIEN_JUDGE
fclose(stdin); fclose(stdout);
#endif
return ;
}
BZOJ 1210
题目4: POJ 1739 Tony's Tour
在一个障碍棋盘上求从左下角到右下角的经过所有非障碍格子的数。
我们只要在最后面加上两行。
.******.
.............
这样就把左下角和右下角在这里边起来了。我们在这个新的棋盘中求回路方案数。那就是答案。
还是很好想的吧。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <iostream> using namespace std; const int maxd = ;
const int State = ;
const int Hash = ;
typedef long long ll; int n, m;
int maze[maxd][maxd];
int code[maxd], ch[maxd];
ll Out_ans;
char str[]; struct HashMap {
int head[Hash], next[State], size;
ll f[State], state[State]; void Init() {
size = ;
memset(head, -, sizeof head);
} void push(ll st, ll ans) {
int h = st % Hash; for(int i = head[h]; i != -; i = next[i]) {
if(state[i] == st) {
f[i] += ans;
return;
}
} f[size] = ans;
state[size] = st;
next[size] = head[h];
head[h] = size ++;
}
}dp[]; void opencode(int *code, int s, ll st) {
for(int i = s; i >= ; -- i) {
code[i] = st & ;
st >>= ;
}
} ll lockcode(int *code, int s) {
int cnt = ;
ll st = ; memset(ch, -, sizeof ch);
ch[] = ;
for(int i = ; i <= s; ++ i) {
if(ch[code[i]] == -)
ch[code[i]] = cnt ++;
code[i] = ch[code[i]];
st <<= ;
st |= code[i];
}
return st;
} void Shit(int *code, int s) {
for(int i = s; i >= ; -- i) {
code[i] = code[i - ];
}
code[] = ;
} void dpblank(int x, int y, int cur) {
int left, up; for(int i = ; i < dp[cur].size; ++ i) {
opencode(code, m, dp[cur].state[i]);
left = code[y - ];
up = code[y]; if(left && up) {
if(left == up) {
if(x == n + && y == m) {
code[y - ] = code[y] = ;
if(y == m) Shit(code, m);
dp[cur ^ ].push(lockcode(code, m), dp[cur].f[i]);
}
}
else {
code[y - ] = code[y] = ;
for(int j = ; j <= m; ++ j)
if(code[j] == up)
code[j] = left;
if(y == m) Shit(code, m);
dp[cur ^ ].push(lockcode(code, m), dp[cur].f[i]);
}
}
else if(((!left) && up) || ((!up) && left)) {
int t = ; if(left) t = left;
else t = up; if(maze[x][y + ]) {
code[y - ] = ; code[y] = t;
dp[cur ^ ].push(lockcode(code, m), dp[cur].f[i]);
}
if(maze[x + ][y]) {
code[y] = ; code[y - ] = t;
if(y == m) Shit(code, m);
dp[cur ^ ].push(lockcode(code, m), dp[cur].f[i]);
}
}
else {
if(maze[x][y + ] && maze[x + ][y]) {
code[y - ] = code[y] = ;
dp[cur ^ ].push(lockcode(code, m), dp[cur].f[i]);
}
}
}
} void dpblock(int x, int y, int cur) {
for(int i = ; i < dp[cur].size; ++ i) {
opencode(code, m, dp[cur].state[i]);
code[y - ] = code[y] = ;
if(y == m) Shit(code, m);
dp[cur ^ ].push(lockcode(code, m), dp[cur].f[i]);
}
} int main() {
while(scanf("%d%d", &n, &m) && n && m) {
memset(maze, , sizeof maze); for(int i = ; i <= n; ++ i) {
scanf("%s", str + );
for(int j = ; j <= m; ++ j) {
if(str[j] == '.')
maze[i][j] = ;
}
}
for(int i = ; i <= m; ++ i) {
maze[n + ][i] = ;
}
maze[n + ][] = ; maze[n + ][m] = ; int cur = ; dp[cur].Init();
dp[cur].push(, );
for(int i = ; i <= n + ; ++ i) {
for(int j = ; j <= m; ++ j) {
dp[cur ^ ].Init();
if(maze[i][j])
dpblank(i, j, cur);
else
dpblock(i, j, cur);
cur ^= ;
}
} Out_ans = ;
for(int i = ; i < dp[cur].size; ++ i) {
Out_ans += dp[cur].f[i];
} printf("%lld\n", Out_ans);
} return ;
}
POJ 1739
插头DP题目泛做(为了对应WYD的课件)的更多相关文章
- 数学期望和概率DP题目泛做(为了对应AD的课件)
题1: Uva 1636 Headshot 题目大意: 给出一个000111序列,注意实际上是环状的.问是0出现的概率大,还是当前是0,下一个还是0的概率大. 问题比较简单,注意比较大小: A/C & ...
- 后缀自动机/回文自动机/AC自动机/序列自动机----各种自动机(自冻鸡) 题目泛做
题目1 BZOJ 3676 APIO2014 回文串 算法讨论: cnt表示回文自动机上每个结点回文串出现的次数.这是回文自动机的定义考查题. #include <cstdlib> #in ...
- 基尔霍夫矩阵题目泛做(AD第二轮)
题目1: SPOJ 2832 题目大意: 求一个矩阵行列式模一个数P后的值.p不一定是质数. 算法讨论: 因为有除法而且p不一定是质数,不一定有逆元,所以我们用辗转相除法. #include < ...
- FFT与多项式、生成函数题目泛做
题目1 COGS 很强的乘法问题 高精度乘法用FFT加速 #include <cstdlib> #include <iostream> #include <algorit ...
- 二维计算几何基础题目泛做(SYX第一轮)
题目1: POJ 2318 TOYS 题目大意: 给一个有n个挡板的盒子,从左到右空格编号为0...n.有好多玩具,问每个玩具在哪个空格里面. 算法讨论: 直接叉积判断就可以.注意在盒子的边界上面也算 ...
- 生成树题目泛做(AD第二轮)
题目1: NOI2014 魔法森林 LCT维护MST.解题报告见LOFTER #include <cstdio> #include <iostream> #include &l ...
- noi往届题目泛做
noi2015 Day1 t1 程序自动分析 离散化+并查集 t2 软件包管理器 裸树链剖分 t3 寿司晚宴 状压dp Day2 t1 荷马史诗 哈夫曼多叉树 t2 品酒大会 后缀数组按照hei ...
- K-D Tree题目泛做(CXJ第二轮)
题目1: BZOJ 2716 题目大意:给出N个二维平面上的点,M个操作,分为插入一个新点和询问到一个点最近点的Manhatan距离是多少. 算法讨论: K-D Tree 裸题,有插入操作. #inc ...
- Link-Cut-Tree题目泛做(为了对应自己的课件)
题目1:BZOJ 2049 洞穴勘测 #include <bits/stdc++.h> #define L(x) c[x][0] #define R(x) c[x][1] using na ...
随机推荐
- cookie自封装对象
cookie.js(设置名值对属性时候不支持设置成前后有空格的格式,如' key'或'key ',只支持‘key’) (function initCookieClass(win){// 定义匿名函数并 ...
- 16 Socket通信(简单例子)
服务端代码: import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.Da ...
- 【3】创建一个简单的Laravel例子
现在我们来创建一个Laravel的例子来帮助理解 1.首先打开app/Http/routes.php文件,在里边写上一条路由: 2.创建一个控制器,有两种方法 ①在app/Http/Controlle ...
- 如何让checkbox复选框只能单选
function框架div 如何让checkbox复选框只能单选 在项目开发中遇到一个这样的问题,要让一列复选框架在任何时间段内只能选择一个. 有人说怎么不用单选框了,因为单选框一旦选择了就不能取消选 ...
- JS判断访问设备、客户端操作系统类型
先给出一个实例:判断windows.linux.android 复制以下代码另存为html文件即可. <html> <head> <title>判断操作系统< ...
- 深入理解 静态类和静态字段(C# 基础)
序言 以前,总是被提醒,在编程过程中尽量少用静态变量,数据丢失什么的,今天有空,禁不住对静态变量的强烈好奇,跟我一起了解下静态家族的内幕吧. 静态类 定义 静态类与非静态类的重要区别在于静态类不能实例 ...
- AFNetworking 使用方法(2.0)
AFNetworking 使用方法(2.0) 分类: IOS2014-11-12 09:17 2018人阅读 评论(0) 收藏 举报 目录(?)[+] 本文介绍的是AFNetworking-2 ...
- Cstring获取第N个字符
void CTestaDlg::GetCStringItemAt(CString strin,CString & strout,int nindex) { ); ; ]={'\0'}; whi ...
- ACdream 1017 Fast Transportation
http://acdream.info/problem?pid=1017 题意:给n个点,m条边,K个货物,要从从S到T,每天每条边最多只能经过1次,求要几天能运完 思路:拆成分层图,每层向下一层连边 ...
- BZOJ 1017 魔兽地图DotR(树形DP)
题意:有两类装备,高级装备A和基础装备B.现在有m的钱.每种B有一个单价和可以购买的数量上限.每个Ai可以由Ci种其他物品合成,给出Ci种其他物品每种需要的数量.每个装备有一个贡献值.求最大的贡献值. ...