zoukankan      html  css  js  c++  java
  • POJ 3133 Manhattan Wiring (插头DP)

    Manhattan Wiring
    Time Limit: 5000MS   Memory Limit: 65536K
    Total Submissions: 1110   Accepted: 634

    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

     
     
    做的第一道的插头DP题目。
    插头DP很难理解,看了很久才看懂别人的程序,然后自己写了下,稍微理解了一点。
    决定快速学会插头DP,写个插头DP的总结,然后学习下概率DP。
     
    应该算是比较基础的插头DP的题目了。就是要把两个2,和两个3连起来,问经过的最少格子数-2。
    普通的插头DP状态转移。
    /*
    POJ 3133
    G++  782ms 1436K
    */
    
    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    
    const int hash_size=60007;
    const int INF=100000;
    
    int n,m;
    int map[20][20];
    int Pow[40];
    
    struct Node
    {
        int hash_chart[hash_size],sz;
        int msk[hash_size];
        int dp[hash_size];
        int next[hash_size];
        void clear()
        {
            sz=0;
            memset(hash_chart,-1,sizeof(hash_chart));
        }
        inline void push(int _msk,int val)
        {
            int x=_msk%hash_size;
            for(int i=hash_chart[x];i!=-1;i=next[i])
            {
                if(msk[i]==_msk)
                {
                    if(dp[i]>val)dp[i]=val;
                    return;
                }
            }
            msk[sz]=_msk;
            dp[sz]=val;
            next[sz]=hash_chart[x];
            hash_chart[x]=sz++;
        }
        inline int res()//得到答案
        {
            int x=0;
            for(int i=hash_chart[x];i!=-1;i=next[i])
              if(!msk[i])
                return dp[i]-2;
            return 0;
        }
    }hh[2];//两个循环转移状态
    
    void solve()
    {
        for(int i=0;i<n;i++)
           for(int j=0;j<m;j++)
             scanf("%d",&map[i][j]);
        int now,pre;
        pre=0;
        now=1;
        hh[pre].clear();
        hh[pre].push(0,0);
        for(int i=0;i<n;i++)
          for(int j=0;j<=m;j++)
          {
              hh[now].clear();
              for(int p=0;p<hh[pre].sz;p++)//从pre的所有状态推到now的状态
              {
                  int k=hh[pre].msk[p];//3进制表示的当前的插头状态
                  int t=hh[pre].dp[p];
                  if(j==m)
                  {
                      if(k/Pow[m])continue;//最后有插头不能转移
                      hh[now].push(k*3,t);
                      continue;
                  }
                  int t1=(k/Pow[j])%3;//
                  int t2=(k/Pow[j+1])%3;//
                  int tk;
                  if(map[i][j]==0)//当前格子为空
                  {
                      if(t1==0&&t2==0)//没有插头
                      {
                          tk=k+Pow[j]+Pow[j+1];//增加2号插头
                          hh[now].push(tk,t+1);
                          tk=k+(Pow[j]<<1)+(Pow[j+1]<<1);//增加3号插头
                          hh[now].push(tk,t+1);
                          tk=k;//不加插头
                          hh[now].push(tk,t);
                      }
                      else if((t1&&(!t2))||(t2&&(!t1)))//只有一个插头
                      {
                          int temp=k-t1*Pow[j]-t2*Pow[j+1];
                          int temps=(!t1)?t2:t1;
                          tk=temp+temps*Pow[j];//插头从下边出来
                          hh[now].push(tk,t+1);
                          tk=temp+temps*Pow[j+1];//插头从右边出来
                          hh[now].push(tk,t+1);
                      }
                      else if((t1==t2)&&t1)//有两个一样的插头
                      {
                          tk=k-t1*Pow[j]-t2*Pow[j+1];//把插头消去
                          hh[now].push(tk,t+1);
                      }
                  }
                  else if(map[i][j]==1)//障碍
                  {
                      if(t1==0&&t2==0)//不能有插头
                      {
                          tk=k;
                          hh[now].push(tk,t);
                      }
                  }
                  else if(map[i][j]==2)//2号
                  {
                      if(t1==0&&t2==0)
                      {
                          tk=k+Pow[j];
                          hh[now].push(tk,t+1);
                          tk=k+Pow[j+1];
                          hh[now].push(tk,t+1);
                      }
                      else if((t1==1&&t2==0)||(t1==0&&t2==1))
                      {
                          tk=k-Pow[j]*t1-Pow[j+1]*t2;
                          hh[now].push(tk,t+1);
                      }
                  }
                  else if(map[i][j]==3)
                  {
                      if(t1==0&&t2==0)
                      {
                          tk=k+(Pow[j]<<1);
                          hh[now].push(tk,t+1);
                          tk=k+(Pow[j+1]<<1);
                          hh[now].push(tk,t+1);
                      }
                      else if((t1==2&&t2==0)||(t1==0&&t2==2))
                      {
                          tk=k-Pow[j]*t1-Pow[j+1]*t2;
                          hh[now].push(tk,t+1);
                      }
                  }
              }
              swap(now,pre);
          }
        printf("%d\n",hh[pre].res());
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        Pow[0]=1;
        for(int i=1;i<20;i++)Pow[i]=3*Pow[i-1];
        while(scanf("%d%d",&n,&m))
        {
            if(n==0&&m==0)break;
            solve();
        }
        return 0;
    }
  • 相关阅读:
    Query实例的ajax应用之二级联动的后台是采用php来做的
    关于jquery的css的一些知识
    这个代码给所有带有name属性的链接加了一个背景色
    jQuery生成一个DIV容器,ID是"rating".
    被included或者被required的文件都来自哪里呢
    msql_createdb: 建立一个新的 mSQL 数据库。
    php中调用这个功能可以在web页面中显示hello world这个经典单词
    啦啦啦测试心得
    maven命令
    robotframework使用
  • 原文地址:https://www.cnblogs.com/kuangbin/p/2707416.html
Copyright © 2011-2022 走看看