这是一道插头DP。。。不会的可以看一下《基于连通性状态压缩的动态规划问题》ppt
然后就是裸题了?
预处理出所有合法的状态,以及每种状态的每个插头匹配的位置,DP时间复杂度O(2^m*n*m)。
分9种情况写的也是乱的。。
#include<iostream>
#include<cstdio>
#include<cstring>
#define inf 1e9
using namespace std;
int n,m,a,tot,dp[2][30000],q[18000],bit[30],Ans=-inf,top,st[100],cnt,now,num,lst;
int S[18000][10];
void pre(int x,int p)
{
top=0;
for(int i=1;i<=m+1;i++,p>>=2)
{
if((p&3)==2)st[++top]=i;
else if((p&3)==1)
{
if(top==0){cnt--;return;}
S[x][st[top]]=i;S[x][i]=st[top];top--;
}
else S[x][i]=0;
}
if(top)cnt--;
}
void Get(int x,int p)
{
if(x>m+1)q[++cnt]=p,pre(cnt,p);
else Get(x+1,p<<2),Get(x+1,p<<2|1),Get(x+1,p<<2|2);
}
void up(int &x,int y){if(y>x)x=y;}
int make(int a,int b)
{
if(a&bit[b<<1])return 1;
if(a&bit[(b<<1)-1])return 2;
return 0;
}
int main()
{
memset(dp,192,sizeof dp);
for(int i=1;i<=20;i++) bit[i]=1<<(i-1);
scanf("%d%d",&n,&m);
Get(1,0);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&a);
lst=tot;tot^=1;
for(int k=1;k<=cnt;k++) dp[lst][q[k]]=-inf;
dp[tot][0]=0;
for(int k=1;k<=cnt;k++)
{
now=q[k];num=dp[tot][now]+a;
int x=make(now,j),y=make(now,j+1);
//以下分类讨论。。
if(!x)
{
if(!y)
{
up(dp[lst][now],dp[tot][now]);
if(i!=n&&j!=m)up(dp[lst][now|bit[j<<1]|bit[((j+1)<<1)-1]],num);
}
else if(y&1)
{
if(j!=m)up(dp[lst][now],num);
if(i!=n)up(dp[lst][now^bit[(j+1)<<1]|bit[j<<1]],num);
}
else if(y&2)
{
if(j!=m)up(dp[lst][now],num);
if(i!=n)up(dp[lst][now^bit[((j+1)<<1)-1]|bit[(j<<1)-1]],num);
}
}
else if(x&1)
{
if(!y)
{
if(i!=n)up(dp[lst][now],num);
if(j!=m)up(dp[lst][now^bit[j<<1]|bit[(j+1)<<1]],num);
}
else if(y&1)
{
up(dp[lst][now^bit[j<<1]^bit[(j+1)<<1]^(bit[(S[k][j+1]<<1)-1]*3)],num);
}
else if(y&2)
{
if((now^bit[j<<1]^bit[((j+1)<<1)-1])==0)up(Ans,num);
}
}
else if(x&2)
{
if(!y)
{
if(i!=n)up(dp[lst][now],num);
if(j!=m)up(dp[lst][now^bit[(j<<1)-1]|bit[((j+1)<<1)-1]],num);
}
else if(y&1)
{
up(dp[lst][now^bit[(j<<1)-1]^bit[(j+1)<<1]],num);
}
else if(y&2)
{
up(dp[lst][now^bit[(j<<1)-1]^bit[((j+1)<<1)-1]^(bit[(S[k][j]<<1)-1]*3)],num);
}
}
}
if(j==m)
{
lst=tot;tot^=1;
for(int k=1;k<=cnt;k++)dp[lst][q[k]]=-inf;
for(int k=1;k<=cnt;k++)dp[lst][q[k]<<2]=dp[tot][q[k]];
}
}
printf("%d\n",Ans);
return 0;
}