来自FallDream的博客,未经允许,请勿转载,谢谢。
给定一个方阵,你要取出一些数字,满足没有两个格子八联通相邻的前提下和最大,求这个和
n<=15
插头dp,保存轮廓线以及目前转移点左上方那个格子的状态,枚举格子转移即可。
#include<iostream> #include<cstdio> #include<cstring> #define MN 15 using namespace std; inline int read() {int x = 0 , f = 1; char ch = getchar();while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();}while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}return x * f; }char st[5000]; int a[MN+5][MN+5],m,f[2][1<<16];int Strread() {int top=0,j=0;for(int i=0;st[i]==' '||(st[i]>='0'&&st[i]<='9');++i)if(st[i]==' ') a[1][++top]=j,j=0;else j=j*10+st[i]-'0';return a[1][++top]=j,top; } inline void R(int&x,int y){y>x?x=y:0;} int main() {while(cin.getline(st,5000)){m=Strread();if(m==1&&a[1][1]==0) continue;for(int i=2;i<=m;++i)for(int j=1;j<=m;++j)a[i][j]=read();memset(f,0,sizeof(f));int now=1,pre=0;for(int i=1;i<=m;++i)for(int j=1;j<=m;++j,swap(now,pre),memset(f[now],0,sizeof(f[now])))for(int k=0;k<1<<(m+1);++k){R(f[now][(k&((1<<m)-(1<<(j-1))-1))|((k&(1<<(j-1)))?(1<<m):0)],f[pre][k]);if((j==1||(!((k&(1<<m)))&&!(k&(1<<(j-2)))))&&!(k&(1<<(j-1)))&&(j==m||!(k&(1<<j))))R(f[now][(k&((1<<m)-1))|(1<<(j-1))|((k&(1<<(j-1)))?(1<<m):0)],f[pre][k]+a[i][j]);}int ans=0;for(int i=0;i<1<<(m+1);++i) ans=max(ans,f[pre][i]);cout<<ans<<endl;}return 0; }