%hz大佬。。这道题的状态压缩简直匪夷所思(其实是我孤陋寡闻,而且我以前的博客竟然写了这题。。水啊)
嗯这题可以发现,我们可以用一个二进制表示一行的状态,1表示选0反之,可以发现行与行之间可选的范围是确定的,比如说:
100
这样的状态适用于每一行,推广一下:
100
001
是适用于任何两行之间的。所以我们可以先将所有成立的状态求出来,要求就是左移一位和右移一位和原状态&运算为0,这样保证每个1左右都没有1。然后枚举行、状态,可以继承的状态,继承可以继承的状态的最大值,然后加上这一行的得到的值即可。
#include<cstdio> #include<iostream> #include<cstring> using namespace std; int n,mp[20][20]; int ol,o[41000],f[20][41000]; bool bj(int x,int y) { return ((x&y)==0)?true:false; } int hehe(int k,int x) { int tp=0,ans=0; while(x!=0) { tp++; if(x%2==1)ans+=mp[k][tp]; x/=2;if(tp==n)break; } return ans; } int main() { scanf("%d",&n); int t=1;for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) scanf("%d",&mp[i][j]); t=t*2; } o[++ol]=0;f[1][0]=0; for(int i=1;i<t;i++) if(bj(i,i/2)==true&&bj(i,i*2)==true) { o[++ol]=i; f[1][i]=hehe(1,i); } for(int k=2;k<=n;k++) { for(int i=1;i<=ol;i++) { for(int j=1;j<=ol;j++) { if(bj(o[i],o[j])==true&&bj(o[i],o[j]/2)==true&&bj(o[i],o[j]*2)==true) { f[k][o[i]]=max(f[k][o[i]],f[k-1][o[j]]); } } f[k][o[i]]+=hehe(k,o[i]); } } int ans=0; for(int i=1;i<=ol;i++) if(f[n][o[i]]>ans)ans=f[n][o[i]]; printf("%d ",ans); return 0; }