跟poj 1185 炮兵阵地差不多。
此题由于士兵不能安排在曼哈顿距离为2的地方。
所以只要不是类似:
第i-2行: 010 | 010 | |
第i-1行: 000 | 100 | 001 |
第i行: 010 | | 010 | 1 01
1】同一列隔一行的位置都有士兵。
2】上下行的隔1位有士兵。
3】同一行隔1个的地方有士兵。
dp[i][k][j]和炮兵阵地表示的意义是一样的。第i行的状态为j,第i-1行的状态为k。
转移方程:dp[i][k][j]=max(dp[i][k][j],dp[i-1][t][k]+num[j])。
就可以了。。
啊啊啊啊啊。。。我本来想直接在炮兵阵地的代码上改,不知道哪里粗心,怎么都是wa。。
后来只得重写一遍。。。。所幸这次1a,。。。快吐了。。。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int dp[202][202][202];
int cur[202],ok[202],num[202];
int maxx(int x,int y)
{
return x>y?x:y;
}
int count_1(int x)
{
int sum=0;
while(x)
{
if(x&1)
sum++;
x>>=1;
}
return sum;
}
int main()
{
int n,m,ans,mp;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(dp,-1,sizeof(dp));
memset(cur,0,sizeof(cur));
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
scanf("%d",&mp);
if(mp==0)
cur[i]|=(1<<j);
}
}
int tot=(1<<m);
int cnt=0;
for(int i=0;i<tot;i++)
{
if((i&(i<<2))==0)
{
ok[cnt]=i;
num[cnt++]=count_1(i);
}
}
for(int i=0;i<cnt;i++)
{
if((ok[i]&cur[0])==0)
dp[0][0][i]=num[i];
}
for(int i=1;i<n;i++)
{
for(int j=0;j<cnt;j++)
{
if(cur[i]&ok[j])
continue;
for(int k=0;k<cnt;k++)
{
if(ok[j]&(ok[k]<<1))
continue;
if(ok[j]&(ok[k]>>1))
continue;
for(int t=0;t<cnt;t++)
{
if((ok[t]&ok[j])||(ok[k]&(ok[t]>>1))||(ok[k]&(ok[t]<<1)))
continue;
if(dp[i-1][t][k]==-1)
continue;
dp[i][k][j]=maxx(dp[i][k][j],dp[i-1][t][k]+num[j]);
}
}
}
}
ans=0;
for(int i=0;i<cnt;i++)
{
for(int j=0;j<cnt;j++)
{
if(ans<dp[n-1][i][j])
ans=dp[n-1][i][j];
}
}
printf("%d\n",ans);
}
return 0;
}