http://poj.org/problem?id=1038
这题废了我n长时间
先把图片旋转下M为横轴N为纵轴
发现题目要求放2x3的方块,所以至少要存三行的状态,考虑三进制状压。
讨论状态
对于
每一个三进制为
都没有被占用
没有占用,
被占用
被占用,
可以不考虑
占用指的是:有坏点或被其他芯片覆盖
通过讨论
来判断
是否可能成为一个芯片的左上角
状态初始化全部为-1,代表不可到达
设置转移
表示第
行状态
时,
行所能放芯片的最大数目
1、这一行的初始状态可以由下一行转移得来
下面
都表示这个坐标对应的状态
当
为0,
为0
当
为1,
为0
当
为2,
为1
特别的当
为坏点,
为2
2、开始dfs过程
参数
表示所到达的列,
代表当前的行
放\不放芯片,讨论的都是
作为左上角位置
分别代表下一行和当前dfs的这一行
- 不放芯片,dfs直接跳转到
- 放竖着的芯片,前提 ,当前已经枚举的放置个数+1转移到 , 表示 放置芯片后的状态 ,dfs跳转到
-
放横着的芯片,前提
,当前已经枚举的放置个数+1转移到
,
表示
放置芯片后的状态
,dfs跳转到
转移就结束了,详细的过程可以在代码中体现
#include <cstdio>
#include <cstring>
#include <iostream>
#define LL long long
using namespace std;
inline void read(int &x){
x = 0; int f = 1; char ch = getchar();
while (!(ch >= '0' && ch <= '9')){if (ch == '-') f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0'; ch = getchar();}
x *= f;
}
inline void Max(int &x, int y){if (y > x) x = y;}
int TT, n, m, k, ans, hit[151][11], f[2][59049], thr[11], p[11], q[11];
bool fg;
inline int make(int *a){//三进制转十进制
int ret = 0;
for (int i = 0; i < m; i++) ret += a[i + 1] * thr[i];
return ret;
}
inline void res(int num, int *a){//十进制转三进制
for (int i = 1; i <= m; i++) a[i] = num % 3, num /= 3;
}
inline void dfs(int x, int cnt){//x表示枚举到的列,cnt表示已经放置芯片的个数
Max(ans, cnt);//更新ans
Max(f[fg][make(q)], cnt);//更新当前q的状态值
for (; x < m; x++){//通过循环省去转移方案1,也可以改为dfs(x+1,cnt),但更慢
//转移方案2
if (p[x] == 0 && p[x + 1] == 0 && q[x] == 0 && q[x + 1] == 0){
q[x] = q[x + 1] = 2;
dfs(x + 2, cnt + 1);
q[x] = q[x + 1] = 0;
}
//转移方案3
//这个位置写成else if好像也能ac,不知为何
if (x <= m - 2 && q[x] == 0 && q[x + 1] == 0 && q[x + 2] == 0){
q[x] = q[x + 1] = q[x + 2] = 2;
dfs(x + 3, cnt + 1);
q[x] = q[x + 1] = q[x + 2] = 0;
}
}
}
int main(){
//预处理3的m次幂
thr[0] = 1;
for (int i = 1; i <= 10; i++) thr[i] = thr[i - 1] * 3;
read(TT);
while (TT--){
//hit表示坏点坐标
memset(hit, 0, sizeof(hit)), memset(f, -1, sizeof(f));
//fg用于滚动数组
fg = 0; ans = 0;
read(n), read(m), read(k);
for (int i = 1, x, y; i <= k; i++) read(x), read(y), hit[x][y] = true;
//预处理第一行,坏点为2,好点为1
for (int i = 1; i <= m; i++) if (hit[1][i]) p[i] = 2; else p[i] = 1;
f[1][make(p)] = 0;
for (int i = 2; i <= n; i++){
//记得初始化
memset(f[fg], -1, sizeof(f[fg]));
for (int j = 0; j < thr[m]; j++) if (f[fg ^ 1][j] != -1){
res(j, p);
for (int o = 1; o <= m; o++){
//状态初始化见上
if (hit[i][o]) q[o] = 2;
else q[o] = max(0, p[o] - 1);
}
dfs(1, f[fg ^ 1][j]);
}
fg ^= 1;
}
printf("%d\n", ans);
}
return 0;
}
从这位dalao学来的%%%
http://www.cnblogs.com/dengeven/p/3237382.html