HDU-1964 Pipes 插头DP
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1964
空白区域之间有权值,求经过所有空白区域的哈密顿回路的最小权值。简单的插头DP,空白区域特殊处理即可。
1 //STATUS:C++_AC_203MS_664KB 2 #include<stdio.h> 3 #include<stdlib.h> 4 #include<string.h> 5 #include<math.h> 6 #include<iostream> 7 #include<string> 8 #include<algorithm> 9 #include<vector> 10 #include<queue> 11 #include<stack> 12 #include<map> 13 using namespace std; 14 #define LL long long 15 #define pii pair<int,int> 16 #define Max(a,b) ((a)>(b)?(a):(b)) 17 #define Min(a,b) ((a)<(b)?(a):(b)) 18 #define mem(a,b) memset(a,b,sizeof(a)) 19 #define lson l,mid,rt<<1 20 #define rson mid+1,r,rt<<1|1 21 const int N=21,INF=0x3f3f3f3f,MOD=40001,STA=8000010; 22 const double DNF=1e13; 23 24 int g[N][N],code[N],ma[N]; 25 int T,n,m,ex,ey; 26 27 struct Hash{ //Hash表,MOD为表长,STA为表大小 28 int first[MOD],next[STA],size; 29 int f[STA]; 30 LL sta[STA]; 31 void init(){ 32 size=0; 33 mem(first,-1); 34 } 35 void add(LL st,int ans){ 36 int i,u=st%MOD; 37 for(i=first[u];i!=-1;i=next[i]){ 38 if(sta[i]==st){ 39 f[i]=Min(f[i],ans); 40 return; 41 } 42 } 43 sta[size]=st; 44 f[size]=ans; 45 next[size]=first[u]; 46 first[u]=size++; 47 } 48 }hs[2]; 49 50 void shift(int p) //换行移位 51 { 52 int k; 53 LL sta; 54 for(k=0;k<hs[!p].size;k++){ 55 sta=hs[!p].sta[k]<<3; 56 hs[p].add(sta,hs[!p].f[k]); 57 } 58 } 59 60 LL getsta() //最小表示法 61 { 62 LL i,cnt=1,sta=0; 63 mem(ma,-1); 64 ma[0]=0; 65 for(i=0;i<=m;i++){ 66 if(ma[code[i]]==-1)ma[code[i]]=cnt++; 67 code[i]=ma[code[i]]; 68 sta|=(LL)code[i]<<(3*i); 69 } 70 return sta; 71 } 72 73 void getcode(LL sta) 74 { 75 int i; 76 for(i=0;i<=m;i++){ 77 code[i]=sta&7; 78 sta>>=3; 79 } 80 } 81 82 void unblock(int i,int j,int p) 83 { 84 int k,t; 85 LL cnt,x,y; 86 for(k=0;k<hs[!p].size;k++){ 87 getcode(hs[!p].sta[k]); 88 x=code[j],y=code[j+1]; 89 cnt=hs[!p].f[k]; 90 if(x && y){ //合并连通分量 91 code[j]=code[j+1]=0; 92 if(x!=y){ 93 for(t=0;t<=m;t++) 94 if(code[t]==y)code[t]=x; 95 hs[p].add(getsta(),cnt+(g[i][j]<10?g[i][j]:0)); 96 } 97 else if(i==ex && j==ey){ //最后一个点特殊处理 98 hs[p].add(getsta(),cnt); 99 } 100 } 101 else if(x&&!y || !x&&y){ //延续连通分量 102 t=x?x:y; 103 if(g[i+1][j]>=0){ 104 code[j]=t;code[j+1]=0; 105 hs[p].add(getsta(),cnt+(g[i][j]<10?g[i][j]:0)); 106 } 107 if(g[i][j+1]>=0){ 108 code[j]=0;code[j+1]=t; 109 hs[p].add(getsta(),cnt+(g[i][j]<10?g[i][j]:0)); 110 } 111 } 112 else { //创建新连通分量 113 if(g[i][j]>=0 && g[i][j]<=9){ 114 hs[p].add(getsta(),cnt); 115 } 116 if(g[i+1][j]>=0 && g[i][j+1]>=0){ 117 code[j]=code[j+1]=8; 118 hs[p].add(getsta(),cnt); 119 } 120 } 121 } 122 } 123 124 void block(LL j,int p) 125 { 126 int k; 127 for(k=0;k<hs[!p].size;k++){ 128 getcode(hs[!p].sta[k]); 129 if(code[j]==0 && code[j+1]==0) 130 hs[p].add(getsta(),hs[!p].f[k]); 131 } 132 } 133 134 int slove() 135 { 136 int i,j,p; 137 hs[0].init(); 138 hs[p=1].init(); 139 hs[0].add(0,0); 140 for(i=0;i<n;i++){ 141 for(j=0;j<m;j++){ 142 if(g[i][j]>=0)unblock(i,j,p); 143 else p=!p; 144 hs[p=!p].init(); 145 } 146 shift(p); //换行移位 147 hs[p=!p].init(); 148 } 149 for(i=0;i<hs[!p].size;i++) 150 if(hs[!p].sta[i]==0)return hs[!p].f[i]; 151 return 0; 152 } 153 154 int main() 155 { 156 // freopen("in.txt","r",stdin); 157 int i,j,ans; 158 char s[N]; 159 scanf("%d",&T); 160 while(T--) 161 { 162 scanf("%d%d",&n,&m); 163 mem(g,-1); 164 n=n*2-1; 165 m=m*2-1; 166 scanf("%s",s); 167 getchar(); 168 for(i=0;i<n;i++){ 169 gets(s); 170 for(j=1;j<=m;j++){ 171 if(s[j]==' ')g[i][j-1]=10; 172 else if(s[j]=='#')g[i][j-1]=-1; 173 else g[i][j-1]=s[j]-'0'; 174 } 175 } 176 scanf("%s",s); 177 ex=n-1,ey=m-1; 178 179 ans=slove(); 180 181 printf("%d\n",ans); 182 } 183 return 0; 184 }