POJ3133 Manhattan Wiring
Posted ONION_CYC
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ3133 Manhattan Wiring相关的知识,希望对你有一定的参考价值。
【算法】插头DP
【题解】蓝书原题
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int MAXD=15; const int MOD=10007; const int STATE=500010; int n,m; int map[MAXD][MAXD]; int code[MAXD]; struct HASHMAP{ int first[MOD],tot,from[STATE],state[STATE],f[STATE]; void init()//清空 { tot=0; memset(first,0,sizeof(first)); } void push(int number,int num)//插入 { int x=number%MOD; for(int i=first[x];i;i=from[i]) if(number==state[i]) { f[i]=min(f[i],num); return;//已有,不用加入,直接return } tot++; state[tot]=number; f[tot]=num; from[tot]=first[x]; first[x]=tot; } }hm[2]; void decode(int st)//解码 { for(int i=m;i>=0;i--)//数组第m位是最右边 { code[i]=(st&3);//\'&\'取出1 st>>=2; } } int encode()//四进制,0无插头 2、3插头 { int st=0; for(int i=0;i<=m;i++) { st<<=2; st|=code[i]; } return st; } void shift()//指向右边界的插头不存在,空出了一位,全体右移一位,把最左插头空出来 { for(int i=m;i>0;i--)code[i]=code[i-1]; code[0]=0; } void dpblank(int i,int j,int cur)//空格map[i][j]=1 { int left,up; for(int k=1;k<=hm[cur].tot;k++) { decode(hm[cur].state[k]); left=code[j-1];//左在本体,本来是j,但因为从0开始编号…… up=code[j]; if(left&&up) { if(left==up)//只接受相同插头 { code[j-1]=code[j]=0;//设置 if(j==m)shift();//过行 hm[cur^1].push(encode(),hm[cur].f[k]+1);//入队 } } else if((left&&(!up))||(!left)&&up) { int t; if(left)t=left;else t=up;//从左或从上 if(map[i][j+1]==1||map[i][j+1]==t)//往右 { code[j-1]=0;code[j]=t; hm[cur^1].push(encode(),hm[cur].f[k]+1); } if(map[i+1][j]==1||map[i+1][j]==t)//往下 { code[j-1]=t;code[j]=0; if(j==m)shift(); hm[cur^1].push(encode(),hm[cur].f[k]+1); } } else { code[j-1]=code[j]=0;//留空 if(j==m)shift(); hm[cur^1].push(encode(),hm[cur].f[k]); if(map[i][j+1]&&map[i+1][j])//开左下插头 { int r=map[i][j+1],d=map[i+1][j]; if(r==1&&(d==1||d==2)||r==2&&(d==1||d==2)) { decode(hm[cur].state[k]);//刚可能换行破坏了,重新解码(挺快的) code[j-1]=code[j]=2; hm[cur^1].push(encode(),hm[cur].f[k]+1); } if(r==1&&(d==1||d==3)||r==3&&(d==1||d==3)) { decode(hm[cur].state[k]); code[j-1]=code[j]=3; hm[cur^1].push(encode(),hm[cur].f[k]+1); } } } } } void dpblock(int i,int j,int cur) { for(int k=1;k<=hm[cur].tot;k++) { decode(hm[cur].state[k]); code[j-1]=code[j]=0; if(j==m)shift(); hm[cur^1].push(encode(),hm[cur].f[k]); } } void dp_begin(int i,int j,int cur,int x)//只接受一个插头(凭空消失)或只从一边出去(凭空出现) { int left,up; for(int k=1;k<=hm[cur].tot;k++) { decode(hm[cur].state[k]); left=code[j-1];up=code[j]; if(left+up==x) { code[j-1]=code[j]=0; if(j==m)shift(); hm[cur^1].push(encode(),hm[cur].f[k]+1);//半条边最后再减掉,避免浮点数运算 } if(left+up==0) { if(map[i][j+1]==1||map[i][j+1]==x) { code[j-1]=0;code[j]=x; hm[cur^1].push(encode(),hm[cur].f[k]+1); } if(map[i+1][j]==1||map[i+1][j]==x) { code[j-1]=x;code[j]=0; if(j==m)shift(); hm[cur^1].push(encode(),hm[cur].f[k]+1); } } } } int main() { scanf("%d%d",&n,&m); while(n!=0||m!=0) { memset(map,0,sizeof(map)); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { int u; scanf("%d",&u); if(u==0)map[i][j]=1; if(u==1)map[i][j]=0; if(u>1)map[i][j]=u; } int cur=0;hm[0].init();hm[0].push(0,0); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { hm[cur^1].init();//根据上一格状态板刷这一格 if(map[i][j]==0)dpblock(i,j,cur); else if(map[i][j]==1)dpblank(i,j,cur); else if(map[i][j]==2)dp_begin(i,j,cur,2); else if(map[i][j]==3)dp_begin(i,j,cur,3); cur^=1; } int ans=0; for(int i=1;i<=hm[cur].tot;i++) ans+=hm[cur].f[i]; if(ans>0)ans-=2; printf("%d\\n",ans); scanf("%d%d",&n,&m); } }
以上是关于POJ3133 Manhattan Wiring的主要内容,如果未能解决你的问题,请参考以下文章
Poj3133Manhattan Wiring (插头DP)