题目:点击打开链接
题意:如图,大炮可以放在p处,黑色区域是可以攻击的范围,问怎么放大炮可以不会误伤,求出最大数?
![](https://i-blog.csdnimg.cn/blog_migrate/ba1d4fa736b99550a7ee43784c287df9.jpeg)
和上一篇poj3254一样,这是这题多加了一个判断,就是还要考虑上上行的情况,其实跟上一题差不多,具体参考代码。
【状态表示】dp[i][j][k] 表示第i行状态为k,第i-1状态为j时的最大炮兵个数。
【状态转移方程】dp[i][k][t] =max(dp[i][k][t],dp[i-1][j][k]+num[t]); num[t]为t状态中1的个数#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
int cur[110],st[60],f[110][60][60],num1[60];
char s[110][12];
int n,m,num;
int count1(int x)
{
int cnt=0;
while(x)
{
cnt++;
x&=(x-1);
}
return cnt;
}
int main()
{
//freopen("f.txt","r",stdin);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%s",s[i]+1);
mem(f,-1);
mem(cur,0);
mem(num1,0);
mem(st,0);
num=0;
for(int i=0;i<(1<<m);i++){
if(i&(i<<1)||i&(i<<2))continue;
else st[++num]=i;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(s[i][j]=='H')cur[i]+=1<<(j-1);
}
}
for(int i=1;i<=num;i++){
num1[i]=count1(st[i]);
if(st[i]&cur[1])continue;
else f[1][1][i]=num1[i];//预处理第1行的状态
}
for(int i=2;i<=n;i++){
for(int j=1;j<=num;j++){ //枚举第i行的可行状态
if(st[j]&cur[i])continue;
for(int k=1;k<=num;k++){ //枚举第i-1行的可行状态
if(st[j]&st[k]||st[k]&cur[i-1])continue;
for(int z=1;z<=num;z++){ //枚举第i-2行的可行状态
if(st[z]&st[j])continue;
if(f[i-1][z][k]!=-1){
f[i][k][j]=max(f[i][k][j],f[i-1][z][k]+num1[j]);
}
}
}
}
}
int ans=0;
for(int j=1;j<=num;j++){
for(int k=1;k<=num;k++)
ans=max(ans,f[n][j][k]);
}
cout<<ans<<endl;
}