USACO 5.4.4 Betsy's Tour
题目大意:
求n*n的网格中,以左上角为起点,以右下角为终点的哈密顿路径的条数。
哈密顿路径:经过且只经过所有点一次的路径。
简单题解:
看到哈密顿路径,我们就自然地想到了基于连通性状态压缩的递推。
参见2008年陈丹琦的论文《基于连通性状态压缩的动态规划问题》。(吐槽:是递推啊。。)
由于路径起点和终点固定,为使问题简单化,我们可以将起点与终点连结起来,转化为哈密顿回路。
为方便转移,将网格顺时针旋转90°。
我的代码:
1 /* 2 ID:t-x.h1 3 LANG:C++ 4 TASK:betsy 5 */ 6 #include<cstdio> 7 #include<cstring> 8 FILE *fi=fopen("betsy.in","r"),*fo=fopen("betsy.out","w"); 9 const int MAXf=999,N=9; 10 int a[MAXf],tot; 11 int brm[MAXf][N],br[N]; 12 int f[N][1<<16]; 13 int main() 14 { 15 int n,m,ans=0,i,j,k,t,p,q; 16 fscanf(fi,"%d",&n); 17 if(n==1) 18 { 19 ans=1; 20 goto to; 21 } 22 m=1<<(n+1)*2; 23 for(i=0;i<m;++i) 24 { 25 for(t=i,j=0,k=0;j<=n;++j,t>>=2) 26 if((t&3)==1) 27 br[k++]=j; 28 else if((t&3)==2) 29 if(k--) 30 brm[tot][br[k]]=j,brm[tot][j]=br[k]; 31 else 32 break; 33 else if((t&3)==3) 34 { 35 k=-1; 36 break; 37 } 38 if(!k) 39 a[tot++]=i; 40 } 41 f[n][(1<<(2*n-1))|1]=1; 42 for(k=1;k<=n;++k) 43 { 44 for(i=0;i<tot;++i) 45 f[0][a[i]]=a[i]&3?0:f[n][a[i]>>2]; 46 for(i=1,t=0;i<=n;++i,t+=2) 47 { 48 memset(f[i],0,sizeof(f[i])); 49 for(j=0;j<tot;++j) 50 { 51 p=(a[j]>>t)&3,q=(a[j]>>(t+2))&3; 52 if(!p && !q) 53 f[i][a[j]|(9<<t)]+=f[i-1][a[j]]; 54 else if(p && q) 55 if(p==q) 56 if(p==1) 57 f[i][a[j]^(5<<t)^(3<<brm[j][i]*2)]+=f[i-1][a[j]]; 58 else 59 f[i][a[j]^(10<<t)^(3<<brm[j][i-1]*2)]+=f[i-1][a[j]]; 60 else 61 if(p==1) 62 { 63 if(k==n && i==n && a[j]==9<<t) 64 ans+=f[i-1][a[j]]; 65 } 66 else 67 f[i][a[j]^(6<<t)]+=f[i-1][a[j]]; 68 else 69 { 70 f[i][a[j]]+=f[i-1][a[j]]; 71 f[i][a[j]^(p<<t)^(q<<(t+2))^(p<<(t+2))^(q<<t)]+=f[i-1][a[j]]; 72 } 73 } 74 } 75 } 76 to: fprintf(fo,"%d\n",ans); 77 fclose(fi); 78 fclose(fo); 79 return 0; 80 }