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;
    }
  • 相关阅读:
    EJB Timer Service is not available. Timers for application with id 95795415990861824 will not be deleted
    MySql数据基本操作sql语句
    python 将字符串转换成字典dict的各种方式总结
    Go语言笔记:struct结构遍历
    golang实现base64编解码
    map赋值前要先初始化:assignment to entry in nil map
    python中 .write 无法向文件写入内容
    python 守护进程
    go语言解析 map[string]interface{} 数据格式
    python虚拟环境--virtualenv
  • 原文地址:https://www.cnblogs.com/kuangbin/p/2707416.html
Copyright © 2011-2022 走看看