题意
- 只有p才可以部署部队,攻击范围是四周两格。求最多能够部署的部队个数。
题解
- dp[i][j][k]表示第i行的状态为j,上一行的状态为k的方案数。
- 从上到下枚举每一行,进行状态压缩。判断相连三个1的个数是否≤1。
- 实际上每一行满足条件的状态数很少,所以可以预处理,只有60种状态。
- 判断这一行与上一行和上上一行是否冲突。如果状态i和j满足i & j = 1,就冲突。
- 因为第一行上面没有,所以特殊判断。
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
int const N = 100 + 5;
int const MAX = 65; //战火会影响两个格子,经过下面的函数Init()计算有60种状态
int mp[N];
int n,m,state[MAX],cnt,sum[MAX];
int dp[N][MAX][MAX];
int lowbit(int x){return x&-x;}
int getsum(int x){ //得到x的二进制1的个数
int num = 0;
while(x){
num++;
x -= lowbit(x); //lowbit函数可用来求解二进制1的个数
}
return num;
}
void Init(){
cnt = 0;
for(int i=0;i<(1<<m);i++){
if((i&(i<<1)) || (i&(i<<2))) continue;
state[++cnt] = i; //记录每行可行的状态
sum[cnt] = getsum(i);
}
}
int solve(){
memset(dp,-1,sizeof(dp));
for(int i=1;i<=cnt;i++){
if(!(state[i] & mp[1])) //枚举第i行的状态
for(int j=1;j<=cnt;j++) //第0行的状态不用判断
dp[1][i][j] = sum[i];
}
int ans = 0;
for(int r=2;r<=n;r++){
for(int i=1;i<=cnt;i++){ //枚举第i行
if(mp[r] & state[i]) continue; //状态与第i行出图
for(int j=1;j<=cnt;j++){ //枚举第i-1行
if(state[i] & state[j]) continue; //第i行与第i-1行冲突
for(int k=1;k<=cnt;k++){ //枚举第i-2行
if(r != 2 && (state[i] & state[k] || state[j] & state[k])) continue; //第i行与第i-2行冲突
if(dp[r-1][j][k] == -1) continue;
dp[r][i][j] = max(dp[r][i][j],dp[r-1][j][k] + sum[i]);
}
}
}
}
for(int i=1;i<=cnt;i++){
for(int j=1;j<=cnt;j++)
ans = max(ans,dp[n][i][j]);
}
return ans;
}
int main(){
while(~scanf("%d%d",&n,&m)){
memset(mp,0,sizeof(mp));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char t; scanf(" %c",&t);
if(t == 'H') mp[i] = mp[i] | (1<<(m-j));
}
}
Init();
printf("%d\n",solve());
}
return 0;
}