和炮兵阵地差不多,要注意几个条件即可。。
题意:n行m列的矩阵,1表示可以放东西,0表示不可以。曼哈顿距离为2的两个位置最多只能有一个位置放东西。
问最多放多少个东西。
对于某一行的状态可以由前面的两行推出。
即:dp[ i ][ j ][ k ] = max( dp[ i ][ j ][ k ] , dp[ i-1 ][ k ] [ k2 ] + ones[ j ] );
其中i-1表示前1行,k2是前2行的状态。
#include"stdio.h"
#include"string.h"
int dp[105][170][170];
int map[170],s[170];
int sum[200];
int max(int a,int b)
{
return a>b?a:b;
}
int ok(int x)
{
if(x&(x<<2))
return 0;
return 1;
}
int main()
{
int n,m,i,j,k,h,x,num,p,r;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(map,0,sizeof(map));
memset(dp,-1,sizeof(dp));
memset(s,0,sizeof(s));
for(i=0;i<n;i++)
for(j=0;j<m;j++)
{
scanf("%d",&h);
if(h==0)
map[i]=map[i]|(1<<j);
}
k=0;
for(i=0;i<(1<<m);i++)
{
if(ok(i))
{
s[k]=i;
x=i;
num=0;
while(x>0)
{
if(x&1)
num++;
x>>=1;
}
sum[k++]=num;
}
}
for(i=0;i<k;i++)
if(!(map[0]&s[i]))
dp[0][i][0]=sum[i];
for(r=1;r<n;r++)
for(i=0;i<k;i++)
{
if(map[r]&s[i])
continue;
for(j=0;j<k;j++)
{
if(s[i]&s[j]<<1)
continue;
if(s[i]&s[j]>>1)
continue;
for(p=0;p<k;p++)
{
if(dp[r-1][j][p]==-1)
continue;
if(s[i]&s[p])
continue;
if(s[j]&s[p]<<1)
continue;
if(s[j]&s[p]>>1)
continue;
dp[r][i][j]=max(dp[r][i][j],dp[r-1][j][p]+sum[i]);
}
}
}
int ans=0;
for(i=0;i<k;i++)
for(j=0;j<k;j++)
{
ans=max(ans,dp[n-1][i][j]);
}
printf("%d\n",ans);
}
return 0;
}