觉得这两道题完全可以写在一起,虽然看起来有点乱,但分开真没什么好写的。
bzoj1187: [HNOI2007]神奇游乐园
题意:在n*m的网格图内找一条简单回路使经过的权值和最大,n<=100,m<=6。
[bzoj2310: ParkII]
题意:在n*m的网格图内找一条简单路径使经过的权值和最大,n<=100,m<=8。
题解
非常典型的插头dp。
逐格转移,根据j和j+1位置的插头情况分类讨论。
t1在形成一条回路并且没有其他插头的时候记录答案。
t2涉及独立插头,状态进制加一位就可以。稍稍剪了一下枝但是效果并没有变好。
代码
比较麻烦,感觉正常写应该不长这样。
//1187:
#include<iostream>
#include<cstdio>
#include<cstring>
#define inf -600001
#define sad 5000000
#define UP1 upd(x,y+1,ncal(),val)
#define UP2 shift(),upd(x+1,0,ncal(),val)
using namespace std;
int n,m,a[101][7],ans=inf;
int dp[101][7][2200];
bool inq[101][7][2200];
int q[sad][3],h,t;
int f[7],lk[7],st[5],T,mxm=1,val;
bool test;
void cal(int v)
{
for(int i=m;i>=0;i--)
f[i]=v%3,v/=3;
T=0;
for(int i=0;i<=m;i++)
if(f[i]==1)
st[T++]=i;
else if(f[i]==2)
lk[st[--T]]=i,lk[i]=st[T];
}
int ncal()
{
int ret=0;
for(int i=0;i<=m;i++)
ret=ret*3+f[i];
return ret;
}
void upd(int i,int j,int k,int v)
{
if(i==n)return;
if(dp[i][j][k]<v)
{
dp[i][j][k]=v;
if(!ncal())ans=max(ans,v);
else if(!inq[i][j][k])
{
inq[i][j][k]=1,
q[t][0]=i,q[t][1]=j,q[t++][2]=k;
if(t==sad)t=0;
}
}
}
void shift()
{for(int i=m;i;i--)f[i]=f[i-1];f[0]=0;}
int x,y,z;
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<=m;i++)
mxm*=3;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
scanf("%d",&a[i][j]);
for(int k=0;k<mxm;k++)
dp[i][j][k]=inf;
}
for(int i=0;i<n-1;i++)
for(int j=1;j<m;j++)
{
for(int k=0;k<=m;k++)
f[k]=0;
f[j-1]=1,f[j]=2;
dp[i][j][ncal()]=a[i][j-1];
q[t][0]=i,q[t][1]=j,q[t++][2]=ncal();
}
while(h!=t)
{
x=q[h][0],y=q[h][1];
cal(z=q[h++][2]);
if(h==sad)h=0;
inq[x][y][z]=0;
val=dp[x][y][z]+a[x][y];
if(f[y]==0&&!f[y+1])
{
if(y<m-1)
upd(x,y+1,z,dp[x][y][z]);
else if(x<n-1)
shift(),upd(x+1,0,ncal(),dp[x][y][z]);
if(x<n-1&&y<m-1)
f[y]=1,f[y+1]=2,UP1;
}
else if(!f[y])
{
if(y<m-1)UP1;
if(x<n-1)
{
f[y]=f[y+1],f[y+1]=0;
if(y==m-1)UP2;
else UP1;
}
}
else if(!f[y+1])
{
if(x<n-1)
{
if(y==m-1)UP2;
else UP1;
}
if(y<m-1)
f[y+1]=f[y],f[y]=0,UP1;
}
else if(f[y]==f[y+1])
{
f[y]=f[y+1]=0;
f[lk[y]]=2,f[lk[y+1]]=1;
if(y<m-1)UP1;
else if(x<n-1)UP2;
}
else if(f[y]==2&&f[y+1]==1)
{
f[y]=f[y+1]=0;
if(y<m-1)UP1;
else if(x<n-1)UP2;
}
else
{
x=0;
for(int i=0;i<=m;i++)
if(f[i])x++;
if(x==2&&ans<val)
ans=val;
}
}
printf("%d",ans);
}
//2310:
#include<cstdio>
#include<cstring>
#define inf 0xefefefef
#define mxs 260000
#define upd if(ans<val)ans=val
using namespace std;
int n,m,ans=inf,tim,T,val,hd;
int dp[mxs][2],q[mxs][2],Tim[mxs];
int a[100][8],f[9],lk[9],t[2]={1},bin[9]={1},st[5];
bool inq[mxs][2],now,sad;
void cal(int S)
{
hd=T=sad=0;
if(!S)sad=1;
for(int i=0;i<=m;i++)
{
f[i]=S&3,S>>=2;
if(f[i]==3)hd++;
else if(f[i]==1)st[T++]=i,sad=1;
else if(f[i]==2)lk[i]=st[--T],lk[st[T]]=i,sad=1;
}
}
int i,j,k,s;
void ad(int S,int v)
{
if(j==m-1)S<<=2;
if(dp[S][now^1]<v||Tim[S]<tim)
{
dp[S][now^1]=v,Tim[S]=tim;
if(!inq[S][now^1])
inq[S][now^1]=1,q[t[now^1]++][now^1]=S;
}
}
int main()
{
memset(dp,0xef,sizeof dp);
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
bin[i]=(bin[i-1]<<2);
for(i=0;i<n;i++)
for(j=0;j<m;j++)
{scanf("%d",&a[i][j]);if(ans<a[i][j])ans=a[i][j];}
dp[0][0]=0;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
{
while(t[now])
{
cal(s=q[--t[now]][now]);
inq[s][now]=0;val=dp[s][now]+a[i][j];
if(dp[s][now]<=0&&!sad)continue;
if(!f[j])
{
if(!f[j+1])
{
if(j+1<m&i+1<n)
ad(s+bin[j]+(bin[j+1]<<1),val);
if(i<n-1||j<m-1)
ad(s,dp[s][now]);
if(a[i][j]>0&&hd<2)
{
if(j+1<m)ad(s+3*bin[j+1],val);
if(i+1<n)ad(s+3*bin[j],val);
}
}
else
{
if(a[i][j]>0)
{
if(f[j+1]<3)
{
if(hd<2)
ad(s-f[j+1]*bin[j+1]+(3-f[lk[j+1]])*bin[lk[j+1]],val);
}
else if(s==f[j+1]*bin[j+1])upd;
}
if(i+1<n)ad(s+f[j+1]*(bin[j]-bin[j+1]),val);
if(j+1<m)ad(s,val);
}
}
else if(!f[j+1])
{
if(a[i][j]>0)
{
if(f[j]<3)
{
if(hd<2)
ad(s-f[j]*bin[j]+(3-f[lk[j]])*bin[lk[j]],val);
}
else if(s==f[j]*bin[j])upd;
}
if(i+1<n)ad(s,val);
if(j+1<m)ad(s+f[j]*(bin[j+1]-bin[j]),val);
}
else
{
s-=f[j+1]*bin[j+1]+f[j]*bin[j];
if(f[j]==3)
{
if(f[j+1]<3)
ad(s+(3-f[lk[j+1]])*bin[lk[j+1]],val);
else if(!s)upd;
}
else if(f[j+1]==3)
ad(s+(3-f[lk[j]])*bin[lk[j]],val);
else if(f[j]==2)
{
if(f[j+1]==1)ad(s,val);
else ad(s+(2-f[lk[j]])*bin[lk[j]],val);
}
else if(f[j+1]==1)
ad(s+(1-f[lk[j+1]])*bin[lk[j+1]],val);
}
}
tim++;now^=1;
}
printf("%d",ans);
}