插头DP
HDU1693 Eat the Trees
不用分左右插头的DP。关键就是逐格递推。行与行之间的转移看轮廓线发现很happy。
1 int a[13][13]; 2 ll dp[13][13][1<<15]; 3 int main() 4 { 5 freopen("input.txt","r",stdin); 6 freopen("output.txt","w",stdout); 7 int T=read(),cs=0; 8 while(T--) 9 { 10 int n=read(),m=read(); 11 for1(i,n)for1(j,m)a[i][j]=read(); 12 dp[0][m][0]=1; 13 for1(i,n) 14 { 15 for0(j,(1<<m)-1)dp[i][0][j<<1]=dp[i-1][m][j]; 16 for1(j,m) 17 for0(k,(1<<(m+1))-1) 18 { 19 int x=1<<(j-1),y=1<<j; 20 if(a[i][j]) 21 { 22 dp[i][j][k]=dp[i][j-1][k^x^y]; 23 if(((k&x)!=0)^((k&y)!=0))dp[i][j][k]+=dp[i][j-1][k]; 24 }else dp[i][j][k]=(!(k&x)&&!(k&y))*dp[i][j-1][k]; 25 } 26 } 27 printf("Case %d: There are %lld ways to eat the trees.\n",++cs,dp[n][m][0]); 28 } 29 return 0; 30 }
URAL1519 Formula 1
真正的插头DP来了。发现很好理解, 写起来略蛋疼。hash表的写法各有各的。注意位运算的优先级。
1 int n,m,head[2][maxn],tot[2],b[20],now,pre; 2 bool a[20][20]; 3 ll dp[2][maxn]; 4 struct edge{int go,id,next;}e[2][maxn]; 5 inline void add(int v,ll w) 6 { 7 int z=v%mod; 8 for5(now,i,z)if(y==v){dp[now][i]+=w;return;} 9 e[now][++tot[now]]=(edge){v,z,head[now][z]};head[now][z]=tot[now]; 10 dp[now][tot[now]]=w; 11 } 12 int main() 13 { 14 freopen("input.txt","r",stdin); 15 freopen("output.txt","w",stdout); 16 for0(i,20)b[i]=i<<1; 17 now=0;pre=1; 18 n=read();m=read();int xx,yy;ll ans=0; 19 for1(i,n)for1(j,m) 20 { 21 char ch=getchar();while(ch!='*'&&ch!='.')ch=getchar();a[i][j]=ch=='.'; 22 if(a[i][j])xx=i,yy=j; 23 } 24 add(0,1); 25 for1(i,n) 26 { 27 for1(j,tot[now])e[now][j].go<<=2; 28 for1(j,m) 29 { 30 swap(now,pre); 31 for1(k,tot[now])head[now][e[now][k].id]=0;tot[now]=0; 32 for1(k,tot[pre]) 33 { 34 int v=e[pre][k].go,x=v>>b[j-1]&3,y=v>>b[j]&3;ll w=dp[pre][k]; 35 if(!a[i][j]){if(x+y==0)add(v,w);} 36 else if(x+y==0) 37 { 38 if(!a[i][j+1]||!a[i+1][j])continue; 39 add(v^(1<<b[j-1])^(2<<b[j]),w); 40 } 41 else if(!x&&y) 42 { 43 if(a[i][j+1])add(v,w); 44 if(a[i+1][j])add(v^(y<<b[j-1])^(y<<b[j]),w); 45 }else if(x&&!y) 46 { 47 if(a[i+1][j])add(v,w); 48 if(a[i][j+1])add(v^(x<<b[j-1])^(x<<b[j]),w); 49 }else if(x+y==2) 50 { 51 int t1=1,t2; 52 for2(l,j+1,m) 53 { 54 t2=v>>b[l]&3; 55 if(t2==1)t1++; 56 if(t2==2)t1--; 57 if(!t1){add((v^(x<<b[j-1])^(y<<b[j]))-(1<<b[l]),w);break;} 58 } 59 }else if(x+y==4) 60 { 61 int t1=1,t2; 62 for3(l,j-2,0) 63 { 64 t2=v>>b[l]&3; 65 if(t2==2)t1++; 66 if(t2==1)t1--; 67 if(!t1){add((v^(x<<b[j-1])^(y<<b[j]))+(1<<b[l]),w);break;} 68 } 69 }else if(x==2&&y==1)add(v^(x<<b[j-1])^(y<<b[j]),w); 70 else if(i==xx&&j==yy)ans+=w; 71 } 72 } 73 } 74 cout<<ans<<endl; 75 return 0; 76 }
HDU1964 Pipes
套上面的代码,把取和改成取min。什么?你说读入?读入优化大法好。直接过滤无用字符。
1 int n,m,head[2][maxn],tot[2],b[20],now,pre,dp[2][maxn],a[20][20],c[20][20]; 2 struct edge{int go,id,next;}e[2][maxn]; 3 inline void add(int v,int w) 4 { 5 int z=v%mod; 6 for5(now,i,z)if(y==v){dp[now][i]=min(dp[now][i],w);return;} 7 e[now][++tot[now]]=(edge){v,z,head[now][z]};head[now][z]=tot[now]; 8 dp[now][tot[now]]=w; 9 } 10 inline bool check(int x,int y){return x>=1&&x<=n&&y>=1&&y<=m;} 11 int main() 12 { 13 freopen("input.txt","r",stdin); 14 freopen("output.txt","w",stdout); 15 for0(i,20)b[i]=i<<1; 16 int T=read(); 17 while(T--) 18 { 19 now=0;pre=1; 20 n=read();m=read();int ans=inf; 21 memset(a,0,sizeof(a));memset(c,0,sizeof(c)); 22 for2(i,2,2*n)for1(j,i&1?m:m-1)i&1?c[i>>1][j]=read():a[i>>1][j]=read(); 23 add(0,0); 24 for1(i,n) 25 { 26 for1(j,tot[now])e[now][j].go<<=2; 27 for1(j,m) 28 { 29 swap(now,pre); 30 for1(k,tot[now])head[now][e[now][k].id]=0;tot[now]=0; 31 for1(k,tot[pre]) 32 { 33 int v=e[pre][k].go,x=v>>b[j-1]&3,y=v>>b[j]&3,w=dp[pre][k]; 34 if(x+y==0) 35 { 36 if(!check(i,j+1)||!check(i+1,j))continue; 37 add(v^(1<<b[j-1])^(2<<b[j]),w+c[i][j]+a[i][j]); 38 } 39 else if(!x&&y) 40 { 41 if(check(i,j+1))add(v,w+a[i][j]); 42 if(check(i+1,j))add(v^(y<<b[j-1])^(y<<b[j]),w+c[i][j]); 43 }else if(x&&!y) 44 { 45 if(check(i+1,j))add(v,w+c[i][j]); 46 if(check(i,j+1))add(v^(x<<b[j-1])^(x<<b[j]),w+a[i][j]); 47 }else if(x+y==2) 48 { 49 int t1=1,t2; 50 for2(l,j+1,m) 51 { 52 t2=v>>b[l]&3; 53 if(t2==1)t1++; 54 if(t2==2)t1--; 55 if(!t1){add((v^(x<<b[j-1])^(y<<b[j]))-(1<<b[l]),w);break;} 56 } 57 }else if(x+y==4) 58 { 59 int t1=1,t2; 60 for3(l,j-2,0) 61 { 62 t2=v>>b[l]&3; 63 if(t2==2)t1++; 64 if(t2==1)t1--; 65 if(!t1){add((v^(x<<b[j-1])^(y<<b[j]))+(1<<b[l]),w);break;} 66 } 67 }else if(x==2&&y==1)add(v^(x<<b[j-1])^(y<<b[j]),w); 68 else if(i==n&&j==m)ans=min(ans,w); 69 } 70 } 71 } 72 cout<<ans<<endl; 73 } 74 return 0; 75 }
POJ1739 Tony's Tour
套上上面的代码,强行把欧拉路改成欧拉回路,在棋盘下面加两行即可。
1 int n,m,head[2][maxn],tot[2],b[20],now,pre; 2 bool a[20][20]; 3 ll dp[2][maxn]; 4 struct edge{int go,id,next;}e[2][maxn]; 5 inline void add(int v,ll w) 6 { 7 int z=v%mod; 8 for5(now,i,z)if(y==v){dp[now][i]+=w;return;} 9 e[now][++tot[now]]=(edge){v,z,head[now][z]};head[now][z]=tot[now]; 10 dp[now][tot[now]]=w; 11 } 12 int main() 13 { 14 freopen("input.txt","r",stdin); 15 freopen("output.txt","w",stdout); 16 for0(i,20)b[i]=i<<1; 17 now=0;pre=1; 18 while(1) 19 { 20 n=read();m=read();ll ans=0; 21 memset(a,0,sizeof(a)); 22 if(!n&&!m)break; 23 for1(i,n)for1(j,m) 24 { 25 char ch=getchar();while(ch!='#'&&ch!='.')ch=getchar();a[i][j]=ch=='.'; 26 } 27 for1(i,m)if(i==1||i==m)a[n+1][i]=1;else a[n+1][i]=0; 28 for1(i,m)a[n+2][i]=1; 29 n+=2; 30 add(0,1); 31 for1(i,n) 32 { 33 for1(j,tot[now])e[now][j].go<<=2; 34 for1(j,m) 35 { 36 swap(now,pre); 37 for1(k,tot[now])head[now][e[now][k].id]=0;tot[now]=0; 38 for1(k,tot[pre]) 39 { 40 int v=e[pre][k].go,x=v>>b[j-1]&3,y=v>>b[j]&3;ll w=dp[pre][k]; 41 if(!a[i][j]){if(x+y==0)add(v,w);} 42 else if(x+y==0) 43 { 44 if(!a[i][j+1]||!a[i+1][j])continue; 45 add(v^(1<<b[j-1])^(2<<b[j]),w); 46 } 47 else if(!x&&y) 48 { 49 if(a[i][j+1])add(v,w); 50 if(a[i+1][j])add(v^(y<<b[j-1])^(y<<b[j]),w); 51 }else if(x&&!y) 52 { 53 if(a[i+1][j])add(v,w); 54 if(a[i][j+1])add(v^(x<<b[j-1])^(x<<b[j]),w); 55 }else if(x+y==2) 56 { 57 int t1=1,t2; 58 for2(l,j+1,m) 59 { 60 t2=v>>b[l]&3; 61 if(t2==1)t1++; 62 if(t2==2)t1--; 63 if(!t1){add((v^(x<<b[j-1])^(y<<b[j]))-(1<<b[l]),w);break;} 64 } 65 }else if(x+y==4) 66 { 67 int t1=1,t2; 68 for3(l,j-2,0) 69 { 70 t2=v>>b[l]&3; 71 if(t2==2)t1++; 72 if(t2==1)t1--; 73 if(!t1){add((v^(x<<b[j-1])^(y<<b[j]))+(1<<b[l]),w);break;} 74 } 75 }else if(x==2&&y==1)add(v^(x<<b[j-1])^(y<<b[j]),w); 76 else if(i==n&&j==m)ans+=w; 77 } 78 } 79 } 80 cout<<ans<<endl; 81 } 82 return 0; 83 }
HDU3377 Plan
套上上面的代码。。。卧槽这都什么题啊。。。求路径补成回路,在外面加一圈权值非常大的。
1 int n,m,head[2][maxn],tot[2],b[20],now,pre; 2 ll a[20][20],dp[2][maxn]; 3 struct edge{int go,id,next;}e[2][maxn]; 4 inline void add(int v,ll w) 5 { 6 int z=v%mod; 7 for5(now,i,z)if(y==v){dp[now][i]=max(dp[now][i],w);return;} 8 e[now][++tot[now]]=(edge){v,z,head[now][z]};head[now][z]=tot[now]; 9 dp[now][tot[now]]=w; 10 } 11 inline bool check(int x,int y){return x>=1&&x<=n&&y>=1&&y<=m;} 12 int main() 13 { 14 freopen("input.txt","r",stdin); 15 freopen("output.txt","w",stdout); 16 for0(i,20)b[i]=i<<1;int cs=0; 17 while(scanf("%d%d",&n,&m)!=EOF) 18 { 19 now=0;pre=1; 20 ll ans=-inf; 21 memset(a,0,sizeof(a)); 22 n+=2;m+=2; 23 for1(i,m)a[1][i]=inf; 24 for1(i,n)a[i][m]=inf; 25 a[2][1]=a[n][m-1]=inf; 26 for2(i,2,m-1)a[2][i]=-inf; 27 for2(i,2,n-1)a[i][m-1]=-inf; 28 for2(i,3,n)for1(j,m-2)a[i][j]=read(); 29 //for1(i,n)for1(j,m)printf("%I64d%c",a[i][j],j==m?'\n':' '); 30 memset(head,0,sizeof(head));tot[0]=tot[1]=0; 31 add(0,0); 32 for1(i,n) 33 { 34 for1(j,tot[now])e[now][j].go<<=2; 35 for1(j,m) 36 { 37 swap(now,pre); 38 for1(k,tot[now])head[now][e[now][k].id]=0;tot[now]=0; 39 for1(k,tot[pre]) 40 { 41 int v=e[pre][k].go,x=v>>b[j-1]&3,y=v>>b[j]&3;ll w=dp[pre][k]; 42 if(x+y==0) 43 { 44 add(v,w); 45 if(!check(i,j+1)||!check(i+1,j))continue; 46 add(v^(1<<b[j-1])^(2<<b[j]),w+a[i][j]); 47 } 48 else if(!x&&y) 49 { 50 if(check(i,j+1))add(v,w+a[i][j]); 51 if(check(i+1,j))add(v^(y<<b[j-1])^(y<<b[j]),w+a[i][j]); 52 }else if(x&&!y) 53 { 54 if(check(i+1,j))add(v,w+a[i][j]); 55 if(check(i,j+1))add(v^(x<<b[j-1])^(x<<b[j]),w+a[i][j]); 56 }else if(x+y==2) 57 { 58 int t1=1,t2; 59 for2(l,j+1,m) 60 { 61 t2=v>>b[l]&3; 62 if(t2==1)t1++; 63 if(t2==2)t1--; 64 if(!t1){add((v^(x<<b[j-1])^(y<<b[j]))-(1<<b[l]),w+a[i][j]);break;} 65 } 66 }else if(x+y==4) 67 { 68 int t1=1,t2; 69 for3(l,j-2,0) 70 { 71 t2=v>>b[l]&3; 72 if(t2==2)t1++; 73 if(t2==1)t1--; 74 if(!t1){add((v^(x<<b[j-1])^(y<<b[j]))+(1<<b[l]),w+a[i][j]);break;} 75 } 76 }else if(x==2&&y==1)add(v^(x<<b[j-1])^(y<<b[j]),w+a[i][j]); 77 else if(i==n&&j==m)ans=max(ans,w+a[i][j]); 78 } 79 } 80 } 81 printf("Case %d: ",++cs);cout<<(ans-(ll)(m+n+1)*inf)<<endl; 82 } 83 return 0; 84 }
SCOI2011地板
这才叫插头DP题嘛!用0表示此处无插头,1表示有但是还需要转弯,2表示有并且不需要转弯。
转移:
00->01|10|22
10->20|01
01->10|02
20->00|02
02->00|20
11->00
1 int n,m,head[2][maxn],tot[2],b[20],now,pre; 2 bool a[101][101]; 3 ll dp[2][maxn]; 4 struct edge{int go,id,next;}e[2][maxn]; 5 inline void add(int v,ll w) 6 { 7 //cout<<v<<' '<<w<<endl; 8 int z=v%p; 9 for5(now,i,z)if(y==v){(dp[now][i]+=w)%=mod;return;} 10 e[now][++tot[now]]=(edge){v,z,head[now][z]};head[now][z]=tot[now]; 11 dp[now][tot[now]]=w; 12 } 13 int main() 14 { 15 freopen("input.txt","r",stdin); 16 freopen("output.txt","w",stdout); 17 for0(i,20)b[i]=i<<1; 18 n=read();m=read(); 19 for1(i,n)for1(j,m) 20 { 21 char ch=getchar();while(ch!='*'&&ch!='_')ch=getchar(); 22 if(n>m)a[i][j]=ch=='_';else a[j][i]=ch=='_'; 23 } 24 if(n<m)swap(n,m); 25 now=0;pre=1; 26 add(0,1); 27 for1(i,n) 28 { 29 //cout<<tot[now]<<endl; 30 for1(j,tot[now])e[now][j].go<<=2; 31 for1(j,m) 32 { 33 swap(now,pre); 34 for1(k,tot[now])head[now][e[now][k].id]=0;tot[now]=0; 35 for1(k,tot[pre]) 36 { 37 int v=e[pre][k].go,x=v>>b[j-1]&3,y=v>>b[j]&3;ll w=dp[pre][k]; 38 if(!a[i][j]){if(x+y==0)add(v,w);} 39 else if(x+y==0) 40 { 41 if(a[i+1][j])add(v^(1<<b[j-1]),w); 42 if(a[i][j+1])add(v^(1<<b[j]),w); 43 if(a[i+1][j]&&a[i][j+1])add(v^(2<<b[j-1])^(2<<b[j]),w); 44 }else if(x==1&&!y) 45 { 46 if(a[i+1][j])add(v+(1<<b[j-1]),w); 47 if(a[i][j+1])add(v^(1<<b[j-1])^(1<<b[j]),w); 48 }else if(!x&&y==1) 49 { 50 if(a[i][j+1])add(v+(1<<b[j]),w); 51 if(a[i+1][j])add(v^(1<<b[j-1])^(1<<b[j]),w); 52 }else if(x==2&&!y) 53 { 54 add(v^(2<<b[j-1]),w); 55 if(a[i][j+1])add(v^(2<<b[j-1])^(2<<b[j]),w); 56 }else if(!x&&y==2) 57 { 58 add(v^(2<<b[j]),w); 59 if(a[i+1][j])add(v^(2<<b[j-1])^(2<<b[j]),w); 60 }else if(x==1&&y==1) 61 { 62 add(v^(1<<b[j-1])^(1<<b[j]),w); 63 } 64 } 65 } 66 } 67 cout<<(tot[now]?dp[now][1]:0)<<endl; 68 return 0; 69 }
HNOI2004邮递员
插头DP求回路。加个高精度。AC了之后发现时光机说这题有点问题。Orz
1 int n,m,head[2][maxm],tot[2],b[20],now,pre; 2 bool a[20][20]; 3 struct edge{int go,id,next;}e[2][maxn]; 4 struct bignum 5 { 6 int x[10],n; 7 void init(int b) 8 { 9 memset(x,0,sizeof(x)); 10 x[n=1]=b; 11 } 12 void rebuild() 13 { 14 for(int i=1;i<=n||x[i];i++) 15 { 16 x[i+1]+=x[i]/bs; 17 x[i]%=bs; 18 if(i>n)n=i; 19 } 20 } 21 void operator +=(bignum b) 22 { 23 n=max(n,b.n); 24 for1(i,n)x[i]+=b.x[i]; 25 this->rebuild(); 26 } 27 void print() 28 { 29 printf("%d",x[n]); 30 for3(i,n-1,1)printf("%04d",x[i]); 31 printf("\n"); 32 } 33 void operator *=(int b) 34 { 35 for1(i,n)x[i]*=b; 36 this->rebuild(); 37 } 38 }dp[2][maxn]; 39 inline void add(int v,bignum w) 40 { 41 int z=v%mod; 42 for5(now,i,z)if(y==v){dp[now][i]+=w;return;} 43 e[now][++tot[now]]=(edge){v,z,head[now][z]};head[now][z]=tot[now]; 44 dp[now][tot[now]]=w; 45 } 46 int main() 47 { 48 freopen("input.txt","r",stdin); 49 freopen("output.txt","w",stdout); 50 for0(i,20)b[i]=i<<1; 51 now=0;pre=1; 52 n=read();m=read();if(n<m)swap(n,m); 53 if(m==1){printf("%d\n",1);return 0;} 54 for1(i,n)for1(j,m)a[i][j]=1; 55 bignum ans;ans.init(1); 56 add(0,ans); 57 ans.init(0); 58 for1(i,n) 59 { 60 for1(j,tot[now])e[now][j].go<<=2; 61 for1(j,m) 62 { 63 swap(now,pre); 64 for1(k,tot[now])head[now][e[now][k].id]=0;tot[now]=0; 65 for1(k,tot[pre]) 66 { 67 int v=e[pre][k].go,x=v>>b[j-1]&3,y=v>>b[j]&3;bignum w=dp[pre][k]; 68 if(!a[i][j]){if(x+y==0)add(v,w);} 69 else if(x+y==0) 70 { 71 if(!a[i][j+1]||!a[i+1][j])continue; 72 add(v^(1<<b[j-1])^(2<<b[j]),w); 73 } 74 else if(!x&&y) 75 { 76 if(a[i][j+1])add(v,w); 77 if(a[i+1][j])add(v^(y<<b[j-1])^(y<<b[j]),w); 78 }else if(x&&!y) 79 { 80 if(a[i+1][j])add(v,w); 81 if(a[i][j+1])add(v^(x<<b[j-1])^(x<<b[j]),w); 82 }else if(x+y==2) 83 { 84 int t1=1,t2; 85 for2(l,j+1,m) 86 { 87 t2=v>>b[l]&3; 88 if(t2==1)t1++; 89 if(t2==2)t1--; 90 if(!t1){add((v^(x<<b[j-1])^(y<<b[j]))-(1<<b[l]),w);break;} 91 } 92 }else if(x+y==4) 93 { 94 int t1=1,t2; 95 for3(l,j-2,0) 96 { 97 t2=v>>b[l]&3; 98 if(t2==2)t1++; 99 if(t2==1)t1--; 100 if(!t1){add((v^(x<<b[j-1])^(y<<b[j]))+(1<<b[l]),w);break;} 101 } 102 }else if(x==2&&y==1)add(v^(x<<b[j-1])^(y<<b[j]),w); 103 else if(i==n&&j==m)ans+=w; 104 //if(x==1&&y==2)add(v^(x<<b[j-1])^(y<<b[j]),w); 105 } 106 } 107 } 108 ans*=2; 109 ans.print(); 110 return 0; 111 }