寻找经过所有必须经过的点的哈密顿回路数。与Ural 1519类似,在求解答案时加入一个判断:当前是否走过了所有的必须经过的点,是否形成回路。
插头DP入门可看上一篇博客:http://blog.csdn.net/sf____/article/details/15026397
括号序列代码如下:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define LL long long const int maxn=100013; struct Node { int H[maxn]; LL N[maxn]; int S[maxn]; int size; void init() { size=0; memset(H,-1,sizeof(H)); } void push(int SS,LL num) { int s=SS%maxn; while( ~H[s] && S[H[s]]!=SS ) s=(s+1)%maxn; if( ~H[s] ) { N[H[s]]+=num; return ; } S[size]=SS; N[size]=num; H[s]=size++; } } dp[2]; int now,pre; int maze[14][14]; int get(int S,int p,int l=2) { return (S>>(p*l))&((1<<l)-1); } void set(int &S,int p,int v,int l=2) { S^=get(S,p,l)<<(p*l); S^=(v&((1<<l)-1))<<(p*l); } int main() { int cas=1; int n,m; int T; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); LL ans=0; int endx,endy; memset(maze,0,sizeof(maze)); for(int i=0;i<n;i++) { char str[20]; scanf("%s",str); for(int j=0;j<m;j++) { switch(str[j]) { case 'X': maze[i][j]=0; break; case 'O': endx=i; endy=j; maze[i][j]=1; break; case '*': maze[i][j]=-1; break; } } } now=1; pre=0; dp[now].init(); dp[now].push(0,1); for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { swap(now,pre); dp[now].init(); for(int s=0;s<dp[pre].size;s++) { int S=dp[pre].S[s]; LL num=dp[pre].N[s]; int p=get(S,j); int q=get(S,j+1); if(maze[i][j]==0) { if(p==0 && q==0) dp[now].push(S,num); continue; } if(p==0 && q==0) { if(maze[i][j]==-1) dp[now].push(S,num); if(maze[i][j+1] && maze[i+1][j]) { set(S,j,1); set(S,j+1,2); dp[now].push(S,num); } } else if(p==2 && q==1) { set(S,j,0); set(S,j+1,0); dp[now].push(S,num); } else if( (p>0)^(q>0) ) { if(maze[i+(p>0)][j+(q>0)]) dp[now].push(S,num); set(S,j,q); set(S,j+1,p); if(maze[i+(q>0)][j+(p>0)]) dp[now].push(S,num); } else if( p==1 && q==1 ) { int find=1; for(int k=j+2;k<=m;k++) { int v=get(S,k); if(v==2) find--; else if(v==1) find++; if(find==0) { set(S,j,0); set(S,j+1,0); set(S,k,1); dp[now].push(S,num); break; } } } else if( p==2 && q==2 ) { int find=1; for(int k=j-1;k>=0;k--) { int v=get(S,k); if(v==1) find--; else if(v==2) find++; if(find==0) { set(S,j,0); set(S,j+1,0); set(S,k,2); dp[now].push(S,num); break; } } } else if( p==1 && q==2 ) { set(S,j,0); set(S,j+1,0); if(S==0 && (i>endx || (i==endx && j>=endy))) ans+=num; } } } for(int s=0;s<dp[now].size;s++) dp[now].S[s]<<=2; } printf("Case %d: %I64d\n",cas++,ans); } }
最小表示法代码如下:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; const int maxn=59999; const int L=3; int now,pre; int n,m; LL ans; int endx,endy; int maze[15][15]; int code[15],ch[15]; struct Node { int h[maxn]; LL n[maxn]; LL s[maxn]; int size; void init() { memset(h,-1,sizeof(h)); size=0; } void push(LL ss,LL num) { int i=ss%maxn; while( ~h[i] && s[h[i]]!=ss ) i=(i+1)%maxn; if( ~h[i] ) { n[h[i]]+=num; } else { s[size]=ss; n[size]=num; h[i]=size++; } } } dp[2]; void decode(LL s) { for(int i=0;i<=m;i++) code[i]=s&((1<<L)-1),s>>=L; } LL encode() { memset(ch,-1,sizeof(ch)); ch[0]=0; LL s=0; int cnt=1; for(int i=m;i>=0;i--) { if( ch[code[i]]==-1 ) ch[code[i]]=cnt++; s<<=L; s|=ch[code[i]]; } return s; } void shift() { for(int s=0;s<dp[now].size;s++) dp[now].s[s]<<=L; } void merge(int a,int b) { for(int i=0;i<=m;i++) if(code[i]==a) code[i]=b; } void doGrid(int i,int j) { for(int s=0;s<dp[pre].size;s++) { decode(dp[pre].s[s]); LL n=dp[pre].n[s]; int left=code[j]; int up=code[j+1]; int ma=max(left,up); int mi=min(left,up); if(maze[i][j]==0) { if(ma==0) dp[now].push(encode(),n); continue; } if(ma==0) { if(maze[i][j]==1) { dp[now].push(encode(),n); } if(maze[i][j+1] && maze[i+1][j]) { code[j]=code[j+1]=13; dp[now].push(encode(),n); } } else if(mi==0) { if(maze[i+1][j]) { code[j]=ma; code[j+1]=0; dp[now].push(encode(),n); } if(maze[i][j+1]) { code[j]=0; code[j+1]=ma; dp[now].push(encode(),n); } } else if(left==up) { if(i>endx || (i==endx && j>=endy)) { code[j]=0; code[j+1]=0; if(encode()==0) ans+=n; } } else { code[j]=code[j+1]=0; merge(left,up); dp[now].push(encode(),n); } } } void solve() { now=1,pre=0; ans=0; dp[now].init(); dp[now].push(0,1); for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { swap(now,pre); dp[now].init(); doGrid(i,j); } shift(); } } void init() { memset(maze,0,sizeof(maze)); endx=-1; char str[20]; for(int i=0;i<n;i++) { scanf("%s",str); for(int j=0;j<m;j++) { if(str[j]=='O') maze[i][j]=2,endx=i,endy=j; else if(str[j]=='*') maze[i][j]=1; } } } int main() { int T; int cas=1; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); init(); solve(); printf("Case %d: %I64d\n",cas++,ans); } }