P5074 Eat the Trees
国家队队长李佳衡推荐插头DP练习题
不过这个题经过兔队之手真的好简单的样子啊
直接设计状态f[S],S的0/1表示轮廓线上这一位有没有插头
然后考虑继承前一个状态?直接右移1
然后分类讨论吧
考虑上面和左边的是0还是1
case1: 11
那么我们只能把他们在这个合成一个,不能向下右转移,00
case2:10
右边可以随便延伸或者停止,10,01,00
case3:01
好像和case2一样啊
case3:00
好像除了不铺线可以自由发挥啊,也就是说我们可以转移到10,01,11
总结一下,如果为00那我们可以转移到他某位异或
如果已获知为1可以转移到00和异或一样的
11只能转移00
code:
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
int T, n, m, s, c[12][12];
ll f[1 << 13], g[1 << 13];
int main() {
for(scanf("%d", &T); T--;) {
scanf("%d%d", &n, &m);
s = (1 << m + 1);
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j) {
scanf("%d", &c[i][j]);
}
}
for(int i = 0; i < s; ++i)g[i] = 0;
g[0] = 1;
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j) {
for(int k = 0; k < s; ++k)
f[k] = j ? g[k] : (k & 1 ? 0 : g[k >> 1]);//滚动数组
if(!c[i][j])
for(int k = 0; k < s; ++k)g[k] = k >> j & 3 ? 0 : f[k];//不能铺线,最后一定由0,0转移来
else
for(int k = 0; k < s; ++k)g[k] = f[k ^ 3 << j] + ((k >> j & 1) ^ (k >> j + 1 & 1) ? f[k] : 0);//不一样可以再一个转移
//这个是直接做,考虑总结规律?
}
}
printf("%lld\n", g[0]);//有一个插头都不行
}
return 0;
}