Manhattan Wiring
Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 1112 | Accepted: 636 |
Description
There is a rectangular area containing n × m cells. Two cells are marked with “2”, and another two with “3”. Some cells are occupied by obstacles. You should connect the two “2”s and also the two “3”s with non-intersecting lines. Lines can run only vertically or horizontally connecting centers of cells without obstacles.
Lines cannot run on a cell with an obstacle. Only one line can run on a cell at most once. Hence, a line cannot intersect with the other line, nor with itself. Under these constraints, the total length of the two lines should be minimized. The length of a line is defined as the number of cell borders it passes. In particular, a line connecting cells sharing their border has length 1.
Fig. 1(a) shows an example setting. Fig. 1(b) shows two lines satisfying the constraints above with minimum total length 18.
Figure 1: An example of setting and its solution
Input
The input consists of multiple datasets, each in the following format.
n m row1 … rown
n is the number of rows which satisfies 2 ≤ n ≤ 9. m is the number of columns which satisfies 2 ≤ m ≤ 9. Each rowi is a sequence of m digits separated by a space. The digits mean the following.
0:
Empty
1:
Occupied by an obstacle
2:
Marked with “2”
3:
Marked with “3”
The end of the input is indicated with a line containing two zeros separated by a space.
Output
For each dataset, one line containing the minimum total length of the two lines should be output. If there is no pair of lines satisfying the requirement, answer “0
” instead. No other characters should be contained in the output.
Sample Input
5 5 0 0 0 0 0 0 0 0 3 0 2 0 2 0 0 1 0 1 1 1 0 0 0 0 3 2 3 2 2 0 0 3 3 6 5 2 0 0 0 0 0 3 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 2 3 0 5 9 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 2 0 0 0 0 0 2 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 9 9 3 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 9 9 0 0 0 1 0 0 0 0 0 0 2 0 1 0 0 0 0 3 0 0 0 1 0 0 0 0 2 0 0 0 1 0 0 0 0 3 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 9 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 2 0 0
Sample Output
18 2 17 12 0 52 43
Source
Japan 2006
插头DP,上次做这题的时候写了篇报告:http://www.cnblogs.com/kuangbin/archive/2012/09/28/2707416.html
熟悉插头DP后,按照自己的模板风格又写了一遍。
查了好久的错误,插头DP非常容易写错。
/* POJ 3133 连接2的插头为2,连接3的插头为3 没有插头为0 用四进制表示(四进制比三进制高效) G++ 391ms */ #include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> using namespace std; const int MAXD=15; const int HASH=10007; const int STATE=1000010; int N,M; int maze[MAXD][MAXD];//0表示障碍,1是非障碍,2和3 int code[MAXD]; //0表示没有插头,2表示和插头2相连,3表示和插头3相连 struct HASHMAP { int head[HASH],next[STATE],size; int state[STATE]; int dp[STATE]; void init() { size=0; memset(head,-1,sizeof(head)); } void push(int st,int ans) { int i,h=st%HASH; for(i=head[h];i!=-1;i=next[i]) if(state[i]==st) { if(dp[i]>ans)dp[i]=ans; return; } state[size]=st; dp[size]=ans; next[size]=head[h]; head[h]=size++; } }hm[2]; void decode(int *code,int m,int st)//四进制 { int i; for(int i=m;i>=0;i--) { code[i]=(st&3); st>>=2; } } int encode(int *code,int m) { int i; int st=0; for(int i=0;i<=m;i++) { st<<=2; st|=code[i]; } return st; } void shift(int *code,int m)//换行 { for(int i=m;i>0;i--)code[i]=code[i-1]; code[0]=0; } void dpblank(int i,int j,int cur) { int k,left,up; for(k=0;k<hm[cur].size;k++) { decode(code,M,hm[cur].state[k]); left=code[j-1]; up=code[j]; if(left&&up) { if(left==up)//只能是相同的插头 { code[j-1]=code[j]=0; if(j==M)shift(code,M); hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1); } } else if((left&&(!up))||((!left)&&up))//只有一个插头 { int t; if(left)t=left; else t=up;//这里少写个else ,查了好久的错误 if(maze[i][j+1]==1||maze[i][j+1]==t)//插头从右边出来 { code[j-1]=0; code[j]=t; hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1); } if(maze[i+1][j]==1||maze[i+1][j]==t)//插头从下边出来 { code[j]=0; code[j-1]=t; if(j==M)shift(code,M); hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1); } } else if(left==0&&up==0)//没有插头 { code[j-1]=code[j]=0;//不加插头 if(j==M)shift(code,M); hm[cur^1].push(encode(code,M),hm[cur].dp[k]); if(maze[i][j+1]&&maze[i+1][j]) { if(maze[i][j+1]==1&&maze[i+1][j]==1) { decode(code,M,hm[cur].state[k]); code[j-1]=code[j]=2;//加2号插头 hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1); //decode(code,M,hm[cur].state[k]); code[j-1]=code[j]=3;//加3号插头 hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1); } else if((maze[i][j+1]==2&&maze[i+1][j]==1)||(maze[i+1][j]==2&&maze[i][j+1]==1)||(maze[i][j+1]==2&&maze[i+1][j]==2)) { decode(code,M,hm[cur].state[k]); code[j-1]=code[j]=2; hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1); } else if((maze[i][j+1]==3&&maze[i+1][j]==1)||(maze[i+1][j]==3&&maze[i][j+1]==1)||(maze[i][j+1]==3&&maze[i+1][j]==3)) { decode(code,M,hm[cur].state[k]); code[j-1]=code[j]=3; hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1); } } } } } void dpblock(int i,int j,int cur) { int k; for(k=0;k<hm[cur].size;k++) { decode(code,M,hm[cur].state[k]); if(code[j-1]!=0||code[j]!=0)continue; code[j-1]=code[j]=0;//不加插头 if(j==M)shift(code,M); hm[cur^1].push(encode(code,M),hm[cur].dp[k]); } } void dp_2(int i,int j,int cur) { int left,up,k; for(k=0;k<hm[cur].size;k++) { decode(code,M,hm[cur].state[k]); left=code[j-1]; up=code[j]; if((left==2&&up==0)||(left==0&&up==2)) { code[j-1]=code[j]=0; if(j==M)shift(code,M); hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1); } else if(left==0&&up==0) { if(maze[i][j+1]==1||maze[i][j+1]==2) { code[j-1]=0; code[j]=2; hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1); } if(maze[i+1][j]==1||maze[i+1][j]==2) { code[j-1]=2; code[j]=0; if(j==M)shift(code,M); hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1); } } } } void dp_3(int i,int j,int cur) { int left,up,k; for(k=0;k<hm[cur].size;k++) { decode(code,M,hm[cur].state[k]); left=code[j-1]; up=code[j]; if((left==3&&up==0)||(left==0&&up==3)) { code[j-1]=code[j]=0; if(j==M)shift(code,M); hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1); } else if(left==0&&up==0) { if(maze[i][j+1]==1||maze[i][j+1]==3) { code[j-1]=0; code[j]=3; hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1); } if(maze[i+1][j]==1||maze[i+1][j]==3) { code[j-1]=3; code[j]=0; if(j==M)shift(code,M); hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1); } } } } void init() { memset(maze,0,sizeof(maze)); for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) { scanf("%d",&maze[i][j]); //if(maze[i][j]==0)maze[i][j]=1; //if(maze[i][j]==1)maze[i][j]=0; //上面的写法是错的,!!! if(maze[i][j]==1||maze[i][j]==0)maze[i][j]^=1;//0变1,1变0 } } void solve() { int i,j,cur=0; hm[cur].init(); hm[cur].push(0,0); for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) { hm[cur^1].init(); if(maze[i][j]==0)dpblock(i,j,cur); else if(maze[i][j]==1)dpblank(i,j,cur); else if(maze[i][j]==2)dp_2(i,j,cur); else if(maze[i][j]==3)dp_3(i,j,cur); cur^=1; } int ans=0; for(int i=0;i<hm[cur].size;i++) ans+=hm[cur].dp[i]; if(ans>0)ans-=2; printf("%d\n",ans); } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); while(scanf("%d%d",&N,&M)) { if(N==0&&M==0)break; init(); solve(); } return 0; }