uva1214 - Manhattan Wiring 插头DP

There is a rectangular area containing n x 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. 6(a) shows an example setting. Fig. 6(b) shows two lines satisfying the constraints above with minimum total length 18.

Input 

The input consists of multiple datasets, each in the following format.

n    m
row1
$ \vdots$
rown
n  is the number of rows which satisfies  2$ \le$n$ \le$9 m  is the number of columns which satisfies  2$ \le$m$ \le$9 . Each row i  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

 N*M的格子里,有两个2和两个3,把2和2连起来,3和3连起来,连线长度之和最小是多少。连线不能相交,如果无法连接输出0。

 这道题恶心的地方在于有两种插头,所以要用3进制,0表示没插头,1表示2的插头,2表示3的插头。然后就各种转移了。格子上0 的地方要么没有插头,要么有两个同样的插头。1的地方没有插头。2的地方有且只有1个1插头,3的地方有且只有1个2插头。

 dp[i][j][s]表示第i行j列插头状态s的最小值,一开始除了dp[0][M][0]是0外其他都初始化为INF,最后答案是dp[N][M][0]。

 当前行开始状态为上一行最后状态除3,也就是dp[i][j][s]=dp[i-1][M][s*3]。

 要用滚动数组做,要不会超时。就算滚动数组稍微开大一点也要超时。。。

<pre name="code" class="cpp">#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;

const int MAXN=110;
const int MAXM=20010;
const LL MOD=1e9+7;
const int INF=0x3f3f3f3f;

int N,M;
int power[15];
int dp[2][60000];
int a[12][12];

int bit(int s,int n){
    return s%power[M-n+1]/power[M-n];
}

//void print(int s){
//    for(int i=M;i>=0;i--){
//        printf("%d",s/power[i]);
//        s%=power[i];
//    }
//    puts("");
//}
int main(){
    freopen("in.txt","r",stdin);
    power[0]=1;
    for(int i=1;i<12;i++) power[i]=power[i-1]*3;
    while(scanf("%d%d",&N,&M)!=EOF&&(N||M)){
        for(int i=1;i<=N;i++)
            for(int j=1;j<=M;j++) scanf("%d",&a[i][j]);
        memset(dp,INF,sizeof(dp));
        int cur=0;
        dp[cur][0]=0;
        for(int i=1;i<=N;i++){
            cur=!cur;
            memset(dp[cur],INF,sizeof(dp[cur]));
            for(int s=0;s<power[M];s++) dp[cur][s]=dp[1-cur][s*3];
            for(int j=1;j<=M;j++){
                cur=!cur;
                memset(dp[cur],INF,sizeof(dp[cur]));
                for(int s=0;s<power[M+1];s++){
                    int p=bit(s,j),q=bit(s,j-1);
                    if(a[i][j]==0){
                        if(p==0&&q==0){
                            dp[cur][s]=min(dp[cur][s],dp[1-cur][s]);
                            dp[cur][s]=min(dp[cur][s],dp[1-cur][s+power[M-j]+power[M-j+1]]);
                            dp[cur][s]=min(dp[cur][s],dp[1-cur][s+2*power[M-j]+2*power[M-j+1]]);
                        }
                        else if(p==1&&q==0){
                            dp[cur][s]=min(dp[cur][s],dp[1-cur][s]+1);
                            dp[cur][s]=min(dp[cur][s],dp[1-cur][s-power[M-j]+power[M-j+1]]+1);
                        }
                        else if(p==0&&q==1){
                            dp[cur][s]=min(dp[cur][s],dp[1-cur][s]+1);
                            dp[cur][s]=min(dp[cur][s],dp[1-cur][s-power[M-j+1]+power[M-j]]+1);
                        }
                        else if(p==2&&q==0){

                            dp[cur][s]=min(dp[cur][s],dp[1-cur][s]+1);
                            dp[cur][s]=min(dp[cur][s],dp[1-cur][s-2*power[M-j]+2*power[M-j+1]]+1);
                        }
                        else if(p==0&&q==2){
                            dp[cur][s]=min(dp[cur][s],dp[1-cur][s]+1);
                            dp[cur][s]=min(dp[cur][s],dp[1-cur][s-2*power[M-j+1]+2*power[M-j]]+1);
                        }
                        else if(p==1&&q==1){
                            dp[cur][s]=min(dp[cur][s],dp[1-cur][s-power[M-j]-power[M-j+1]]+2);
                        }
                        else if(p==2&&q==2){
                            dp[cur][s]=min(dp[cur][s],dp[1-cur][s-2*power[M-j]-2*power[M-j+1]]+2);
                        }
                    }
                    else if(a[i][j]==1){
                        if(p==0&&q==0) dp[cur][s]=min(dp[cur][s],dp[1-cur][s]);
                    }
                    else if(a[i][j]==2){
                        if(p==0&&q==0){
                            dp[cur][s]=min(dp[cur][s],dp[1-cur][s+power[M-j+1]]);
                            dp[cur][s]=min(dp[cur][s],dp[1-cur][s+power[M-j]]);
                        }
                        else if(p==1&&q==0){
                            dp[cur][s]=min(dp[cur][s],dp[1-cur][s-power[M-j]]+1);
                        }
                        else if(p==0&&q==1){
                            dp[cur][s]=min(dp[cur][s],dp[1-cur][s-power[M-j+1]]+1);
                        }

                    }
                    else if(a[i][j]==3){
                        if(p==0&&q==0){
                            dp[cur][s]=min(dp[cur][s],dp[1-cur][s+2*power[M-j+1]]);
                            dp[cur][s]=min(dp[cur][s],dp[1-cur][s+2*power[M-j]]);
                        }
                        else if(p==2&&q==0){
                            dp[cur][s]=min(dp[cur][s],dp[1-cur][s-2*power[M-j]]+1);
                        }
                        else if(p==0&&q==2){
                            dp[cur][s]=min(dp[cur][s],dp[1-cur][s-2*power[M-j+1]]+1);
                        }
                    }
                }
            }
        }
        if(dp[cur][0]!=INF) printf("%d\n",dp[cur][0]);
        else printf("0\n");
    }
    return 0;
}

 


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值