炮兵布阵
题解:先考虑一维的情况,
d
p
[
i
]
dp[i]
dp[i]前
i
i
i行所最多能摆放的炮兵部队的数量,显然无法满足无后效性,无法递推。再考虑加一维,
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示第
i
i
i行布局为
j
j
j的情况下所最多能摆放的炮兵部队的数量,此时依然无法递推,因为每一个炮兵影响的范围是前后两格和左右两格,所以在第
i
−
1
i-1
i−1行布局为
k
k
k的时候无法分辨与布局
j
j
j是否相容。因此考虑再加一维,
d
p
[
i
]
[
j
]
[
k
]
dp[i][j][k]
dp[i][j][k]表示第
i
i
i行布局为
j
j
j第
i
−
1
i-1
i−1行布局为
k
k
k时最多能摆放的炮兵部队的数量。
d
p
[
i
]
[
j
]
[
k
]
=
m
a
x
{
d
p
[
i
−
1
]
[
k
]
[
m
]
+
n
u
m
[
j
]
}
dp[i][j][k] = max\{dp[i-1][k][m]+num[j]\}
dp[i][j][k]=max{dp[i−1][k][m]+num[j]}此时布局
j
j
j和
k
k
k必须相容,否则
d
p
[
i
]
[
j
]
[
k
]
=
0
dp[i][j][k]= 0
dp[i][j][k]=0。
n
u
m
[
j
]
num[j]
num[j]表示布局为
j
j
j中的炮兵数量。我们发现
j
j
j和
m
m
m必须相容,
k
k
k和
m
m
m必须相容。发现可以满足无后效性。
至于边界即
{
d
p
[
1
]
[
j
]
[
1
]
=
n
u
m
[
j
]
d
p
[
1
]
[
i
]
[
j
]
=
m
a
x
{
d
p
[
1
]
[
j
]
[
1
]
+
n
u
m
[
j
]
}
\begin{cases} dp[1][j][1]=num[j]\\\\ dp[1][i][j] = max\{dp[1][j][1]+num[j] \} \end{cases}
⎩⎪⎨⎪⎧dp[1][j][1]=num[j]dp[1][i][j]=max{dp[1][j][1]+num[j]}
代码
#include<cstdio>
#include<cstring>
#define max(a,b) ((a) > (b) ? (a) : (b))
using namespace std;
int n,m;
char map[110][20], num[110], top;
int state[70], cur[70], dp[110][70][70];
bool ok(int x) {
if((x & (x << 1)) || (x & (x << 2))) return 0;
return 1;
}
int getNum(int x) {
int cnt = 0;
while(x) {
cnt++;
x &= (x - 1);
}
return cnt;
}
void init() {
top = 0;
for(int i = 0; i < (1 << m); ++i)
if(ok(i)) state[++top] = i;
memset(dp,-1,sizeof dp);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
scanf("%d%d",&n,&m);
init();
for(int i = 1; i <= n; ++i)
scanf("%s",map[i] + 1);
for(int i = 1; i <= n; ++i) {
cur[i] = 0;
for(int j = 1; j <= m; ++j){
if(map[i][j] == 'H') cur[i] |= (1 << (j - 1));
}
}
for(int j = 1; j <= top; ++j) {
num[j] = getNum(state[j]);
if((state[j] & cur[1]) == 0)
dp[1][j][1] = num[j];
}
for(int i = 2; i <= n; ++i) { //第i行
for(int j = 1; j <= top; ++j) { //第i行布局为j
if(state[j] & cur[i]) continue;
for(int k = 1; k <= top; ++k) { //第i-1行布局为k
if(state[j] & state[k]) continue;
for(int m = 1; m <= top; ++m) {
if(state[j] & state[m]) continue; // j与m相容
if(state[k] & state[m]) continue; // k与m相容
if(dp[i - 1][k][m] == -1) continue;
dp[i][j][k] = max(dp[i][j][k], dp[i - 1][k][m] + num[j]);
}
}
}
}
int ans = 0;
for(int i = 1; i <= top; ++i)
for(int j = 1; j <= top; ++j) ans = max(ans, dp[n][i][j]);
printf("%d\n",ans);
return 0;
}