#include <stdio.h>
#include <string.h>
#define maxn 200
int sta[maxn][2],ok[maxn][maxn];
int dp[111][maxn][maxn];
int m,n,cnt,map[111];
void prt(int i)
{
int t=i;
while(t)printf("%d",t%2),t>>=1;
puts("");
}
int y(int x,int t)
{
if((x&(~t))==0)
return 1;
return 0;
}
int max(int a,int b)
{
if(a>b)
return a;
return b;
}
void init()
{
for(int i=0; i<((1<<m)-1); ++i)
{
if((i&(i<<2)))continue;
sta[cnt][0]=i;
for(int j=i; j; j-=j&(-j))sta[cnt][1]++;
++cnt;
}
for(int i=0; i<cnt; i++)
for(int j=0; j<cnt; j++)
{
int t1=sta[i][0]&(sta[j][0]>>1);
int t2=sta[i][0]&(sta[j][0]<<1);
ok[i][j]=!(t1|t2);
}
}
int main ()
{
while(scanf ("%d%d",&n,&m)!=EOF)
{
memset(dp,0,sizeof(dp));
memset(sta,0,sizeof(sta));
memset(ok,0,sizeof(ok));
memset(map,0,sizeof(map));
cnt=0;
init();
int x;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
scanf ("%d",&x);
//printf(" %d ",x);
map[i]=(map[i]+x)<<1;
}
map[i]>>=1;
}
for(int i=0; i<cnt; i++)
{
if(y(sta[i][0],map[1]))
dp[1][0][i]=sta[i][1];
}
for(int i=0; i<cnt; i++)
{
for(int j=0; j<cnt; j++)
{
if(y(sta[i][0],map[1])&&y(sta[j][0],map[2])&&ok[i][j])
dp[2][i][j]=max(sta[i][1]+sta[j][1],dp[2][i][j]);
}
}
for(int o=3; o<=n; o++)
{
for(int i=0; i<cnt; i++)
{
if(y(sta[i][0],map[o-1])==0)continue;
for(int j=0; j<cnt; j++)
{
if(y(sta[j][0],map[o])==0)continue;
for(int k=0; k<cnt; k++)
{
if(y(sta[k][0],map[o-2])==0)continue;
if(ok[k][i]&&ok[i][j]&&(sta[k][0]&sta[j][0])==0)
dp[o][i][j]=max(dp[o][i][j],dp[o-1][k][i]+sta[j][1]);
}
}
}
}
int ans=0;
for(int i=0; i<cnt; i++)
for(int j=0; j<cnt; j++)
ans=max(ans,dp[n][i][j]);
printf("%d\n",ans);
}
}
代码挺麻烦的一个状态压缩dp题,貌似是我写的最长代码的了。
其实挺简单,就是一个棋盘,保存两行的状态进行更新,很多二进制判断的地方有小技巧,是看网上的代码