http://poj.org/problem?id=1038
这题废了我n长时间
先把图片旋转下M为横轴N为纵轴
发现题目要求放2x3的方块,所以至少要存三行的状态,考虑三进制状压。
讨论状态
对于
(
x
,
y
)
(x,y)
(x,y)每一个三进制为
0
:
(
x
,
y
)
,
(
x
,
y
−
1
)
0:(x,y),(x,y-1)
0:(x,y),(x,y−1)都没有被占用
1
:
(
x
,
y
)
1:(x,y)
1:(x,y)没有占用,
(
x
,
y
−
1
)
(x,y-1)
(x,y−1)被占用
3
:
(
x
,
y
)
3:(x,y)
3:(x,y)被占用,
(
x
,
y
−
1
)
(x,y-1)
(x,y−1)可以不考虑
占用指的是:有坏点或被其他芯片覆盖
通过讨论
(
x
,
y
)
(x,y)
(x,y)来判断
(
x
,
y
+
1
)
(x,y+1)
(x,y+1)是否可能成为一个芯片的左上角
状态初始化全部为-1,代表不可到达
设置转移
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示第
i
i
i行状态
j
j
j时,
1
…
i
−
1
1…i-1
1…i−1行所能放芯片的最大数目
1、这一行的初始状态可以由下一行转移得来
下面
(
x
,
y
−
1
)
,
(
x
,
y
)
,
(
x
,
y
+
1
)
(x,y-1),(x,y),(x,y+1)
(x,y−1),(x,y),(x,y+1)都表示这个坐标对应的状态
当
(
x
,
y
−
1
)
(x,y-1)
(x,y−1)为0,
(
x
,
y
)
(x,y)
(x,y)为0
当
(
x
,
y
−
1
)
(x,y-1)
(x,y−1)为1,
(
x
,
y
)
(x,y)
(x,y)为0
当
(
x
,
y
−
1
)
(x,y-1)
(x,y−1)为2,
(
x
,
y
)
(x,y)
(x,y)为1
特别的当
(
x
,
y
)
(x,y)
(x,y)为坏点,
(
x
,
y
)
(x,y)
(x,y)为2
2、开始dfs过程
参数
x
x
x表示所到达的列,
i
i
i代表当前的行
(
i
,
x
)
(i,x)
(i,x)放\不放芯片,讨论的都是
(
i
,
x
)
(i,x)
(i,x)作为左上角位置
p
,
q
p,q
p,q分别代表下一行和当前dfs的这一行
- ( i , x ) (i,x) (i,x)不放芯片,dfs直接跳转到 ( i , x + 1 ) (i,x+1) (i,x+1)
- ( i , x ) (i,x) (i,x)放竖着的芯片,前提 p [ x ] = 0 , p [ x + 1 ] = 0 , q [ x ] = 0 , q [ x + 1 ] = 0 p[x]=0,p[x+1]=0,q[x]=0,q[x+1]=0 p[x]=0,p[x+1]=0,q[x]=0,q[x+1]=0,当前已经枚举的放置个数+1转移到 d p [ i + 1 ] [ q ′ ] dp[i+1][q'] dp[i+1][q′], q ′ q' q′表示 q q q放置芯片后的状态 q [ x ] = q [ x + 1 ] = 2 q[x]=q[x+1]=2 q[x]=q[x+1]=2,dfs跳转到 ( i , x + 2 ) (i,x+2) (i,x+2)
-
(
i
,
x
)
(i,x)
(i,x)放横着的芯片,前提
x
≤
m
−
2
,
q
[
x
]
=
0
,
q
[
x
+
1
]
=
0
,
q
[
x
+
2
]
=
0
x\le m-2,q[x]=0,q[x+1]=0,q[x+2]=0
x≤m−2,q[x]=0,q[x+1]=0,q[x+2]=0,当前已经枚举的放置个数+1转移到
d
p
[
i
+
1
]
[
q
′
]
dp[i+1][q']
dp[i+1][q′],
q
′
q'
q′表示
q
q
q放置芯片后的状态
q
[
x
]
=
q
[
x
+
1
]
=
q
[
x
+
2
]
=
2
q[x]=q[x+1]=q[x+2]=2
q[x]=q[x+1]=q[x+2]=2,dfs跳转到
(
i
,
x
+
3
)
(i,x+3)
(i,x+3)
转移就结束了,详细的过程可以在代码中体现
#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