插头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 ...
随机推荐
- ps 换图片的背景颜色
先把图像格式换乘RGB然后调整颜色,不用谢我是活雷锋!www.idouly.com
- LeetCode-Divdend two Integers
题目: Divide two integers without using multiplication, division and mod operator. 思路分析 二分法.将除数不断增倍,而结 ...
- HDU Today--hdu2112
HDU Today Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- mongoexport导出数据
mongoexport用法: /***** Export MongoDB data to CSV, TSV or JSON files.options: --help ...
- Core Data (2)-备用
1.Core Data 是数据持久化存储的最佳方式 2.数据最终的存储类型可以是:SQLite数据库,XML,二进制,内存里,或自定义数据类型 在Mac OS X 10.5Leopard及以后的版本中 ...
- 启动Tomcat一闪而过解决
打开apache-tomcat-6.0.32/bing/catalina.bat在首行添加: set JAVA_HOME=C:\Program Files\Java\jdk1.6.0_07 就可以了.
- 关于box-sizing
http://www.zhangxinxu.com/css3/css3-box-sizing.php box-sizing:border-box; -o-box-sizing:border-box; ...
- hdu 1116 Play on Words
http://acm.hdu.edu.cn/showproblem.php?pid=1116 欧拉通路和欧拉回路 #include <cstdio> #include <cstrin ...
- python 文件中的中文编码解决方法
# -*- coding: utf-8 -*- #查看安装的SDK默认的编码字符集在脚本中可以修改你的编码格式, 方法如下:#sys.getdefaultencoding()#reload(sys)# ...
- Thinkpad E430+CentOS 6.4+ linux-3.10.12内核网卡驱动(无线+有线)配置
配置并编译安装内核模块和内核后,解压附件 firmware.tar.bz2,拷贝其中的rtlwifi文件夹到/lib/firmware下,然后 执行装载内核模块命令: sudo modprobe rt ...