插头DP。格子间有value,求哈密顿回路value和最小。和Ural 1519类似,给每个状态更新最小的value值即可。
代码如下:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn=59999; struct Node { int H[maxn]; int S[maxn]; int N[maxn]; int size; void init() { size=0; memset(H,-1,sizeof(H)); } void push(int SS,int num) { int s=SS%maxn; while( ~H[s] && S[H[s]]!=SS ) { s++; s%=maxn; } if(~H[s]) { N[H[s]]=min(N[H[s]],num); return; } N[size]=num; S[size]=SS; H[s]=size++; } int get(int SS) { int s=SS%maxn; while( ~H[s] && S[H[s]]!=SS) { s++; s%=maxn; } if(~H[s]) return N[H[s]]; else return 0; } } dp[2]; int now,pre; 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 a[12][12]; int b[12][12]; int maze[12][12]; int main() { int T; scanf("%d",&T); while(T--) { int ans=~0U>>2; int n,m; scanf("%d%d%*c",&n,&m); memset(maze,0,sizeof(maze)); for(int i=0;i<n;i++) for(int j=0;j<m;j++) maze[i][j]=1; char str[1000]; gets(str); memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); for(int i=1;i<n;i++) { gets(str); for(int j=1;j<m;j++) a[i-1][j]=str[j*2]-'0'; gets(str); for(int j=0;j<m;j++) b[i][j]=str[j*2+1]-'0'; } gets(str); for(int j=1;j<m;j++) a[n-1][j]=str[j*2]-'0'; gets(str); now=1; pre=0; dp[now].init(); dp[now].push(0,0); 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]; int num=dp[pre].N[s]; int p=get(S,j); int q=get(S,j+1); if(p==0 && q==0) { set(S,j,1); set(S,j+1,2); if(maze[i][j+1] && maze[i+1][j]) dp[now].push(S,num); } else if(p>0 && q==0) { if(maze[i+1][j]) dp[now].push(S,num+a[i][j]); set(S,j,0); set(S,j+1,p); if(maze[i][j+1]) dp[now].push(S,num+a[i][j]); } else if(p==0 && q>0) { if(maze[i][j+1]) dp[now].push(S,num+b[i][j]); set(S,j,q); set(S,j+1,0); if(maze[i+1][j]) dp[now].push(S,num+b[i][j]); } 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+a[i][j]+b[i][j]); 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+a[i][j]+b[i][j]); break; } } } else if(p==2 && q==1) { set(S,j,0); set(S,j+1,0); dp[now].push(S,num+a[i][j]+b[i][j]); } else if(p==1 && q==2) { if(i==n-1 && j==m-1) { set(S,j,0); set(S,j+1,0); dp[now].push(S,num+a[i][j]+b[i][j]); } } } } for(int s=0;s<dp[now].size;s++) dp[now].S[s]<<=2; } printf("%d\n",dp[now].get(0)); } }
最小表示法:
#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; int ans; int endx,endy; int maze[15][15]; int a[15][15]; int b[15][15]; int code[15],ch[15]; struct Node { int h[maxn]; int n[maxn]; LL s[maxn]; int size; void init() { memset(h,-1,sizeof(h)); size=0; } void push(LL ss,int num) { int i=ss%maxn; while( ~h[i] && s[h[i]]!=ss ) i=(i+1)%maxn; if( ~h[i] ) { n[h[i]]=min(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]); int num=dp[pre].n[s]; int left=code[j]; int up=code[j+1]; int ma=max(left,up); int mi=min(left,up); int val=0; if(left) val+=a[i][j]; if(up) val+=b[i][j]; if(ma==0) { if(maze[i][j+1] && maze[i+1][j]) { code[j]=code[j+1]=13; dp[now].push(encode(),num); } } else if(mi==0) { if(maze[i+1][j]) { code[j]=ma; code[j+1]=0; dp[now].push(encode(),num+val); } if(maze[i][j+1]) { code[j]=0; code[j+1]=ma; dp[now].push(encode(),num+val); } } else if(left==up) { if(i==n-1 && j==m-1) { code[j]=0; code[j+1]=0; if(encode()==0) ans=max(ans,num+val); } } else { code[j]=code[j+1]=0; merge(left,up); dp[now].push(encode(),num+val); } } } void solve() { now=1,pre=0; ans=0; dp[now].init(); dp[now].push(0,0); 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() { scanf("%d%d%*c",&n,&m); memset(maze,0,sizeof(maze)); for(int i=0;i<n;i++) for(int j=0;j<m;j++) maze[i][j]=1; char str[1000]; gets(str); memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); for(int i=1;i<n;i++) { gets(str); for(int j=1;j<m;j++) a[i-1][j]=str[j*2]-'0'; gets(str); for(int j=0;j<m;j++) b[i][j]=str[j*2+1]-'0'; } gets(str); for(int j=1;j<m;j++) a[n-1][j]=str[j*2]-'0'; gets(str); } int main() { int T; int cas=1; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); init(); solve(); printf("%d\n",ans); } }