题意就是给你一个地图,有山地有平原,只有平原上能够布置炮兵,并且炮兵之间不能相互攻击,求最多能安置多少个炮兵
做法是用状态压缩dp,转移方程为dp[i][t][k]=max(dp[i][t][k],dp[i-1][j][t]+num[k])......dp[i][t][k]表示的是第i行状态为k,第i-1行状态为t时安置的最大炮兵数
代码如下
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
int n,m,step;
int num[200],cur[200],stk[200],dp[150][150][150];
bool isok(int x) //判断当前行是否能够安置
{
if(x&(x<<1) || x&(x<<2))
return 0;
return 1;
}
int kep(int x) //计算当前状态含有多少个1,也就是最大炮兵个数
{
int cnt=0;
while(x)
{
if(x&1)
cnt++;
x=x>>1;
}
return cnt;
}
void init() //枚举并记录下能够安置的所有状态
{
step=0;
int l=1<<m;
for(int i=0;i<l;i++)
{
if(isok(i))
{
stk[step]=i;
num[step]=kep(i);
step++;
}
}
}
bool judge(int x,int y)
{
if(stk[x]&cur[y])
return 0;
return 1;
}
int MAX(int a,int b)
{
return a>b?a:b;
}
int main()
{
while(~scanf("%d%d",&n,&m) && !(n==m && m==0))
{
int ans=0;
char str[105][105];
init();
memset(dp,-1,sizeof(dp));
for(int i=1;i<=n;i++)
{
scanf("%s",str[i]+1);
cur[i]=0;
for(int j=1;j<=m;j++)
{
if(str[i][j]=='H')
cur[i]|=1<<(m-j);
}
}
for(int i=0;i<step;i++)//单独处理第一行状态
{
if(judge(i,1))
dp[1][0][i]=num[i];
}
for(int i=2;i<=n;i++)//状态转移
{
for(int k=0;k<step;k++)
{
if(!judge(k,i))
continue;
for(int t=0;t<step;t++)
{
if(stk[t]&stk[k])
continue;
for(int j=0;j<step;j++)
{
if(stk[j]&stk[k])
continue;
if(dp[i-1][j][t]==-1)
continue;
dp[i][t][k]=MAX(dp[i][t][k],dp[i-1][j][t]+num[k]);
}
}
}
}
for(int i=1;i<=n;i++)
{
for(int t=0;t<step;t++)
{
for(int k=0;k<step;k++)
{
ans=MAX(ans,dp[i][t][k]);
}
}
}
printf("%d\n",ans);
}
return 0;
}