zoukankan      html  css  js  c++  java
  • HDU-4856 Tunnels (BFS+状压DP)

    Problem Description
    Bob is travelling in Xi’an. He finds many secret tunnels beneath the city. In his eyes, the city is a grid. He can’t enter a grid with a barrier. In one minute, he can move into an adjacent grid with no barrier. Bob is full of curiosity and he wants to visit all of the secret tunnels beneath the city. To travel in a tunnel, he has to walk to the entrance of the tunnel and go out from the exit after a fabulous visit. He can choose where he starts and he will travel each of the tunnels once and only once. Now he wants to know, how long it will take him to visit all the tunnels (excluding the time when he is in the tunnels).
     
    Input
    The input contains mutiple testcases. Please process till EOF.
    For each testcase, the first line contains two integers N (1 ≤ N ≤ 15), the side length of the square map and M (1 ≤ M ≤ 15), the number of tunnels.
    The map of the city is given in the next N lines. Each line contains exactly N characters. Barrier is represented by “#” and empty grid is represented by “.”.
    Then M lines follow. Each line consists of four integers x1, y1, x2, y2, indicating there is a tunnel with entrence in (x1, y1) and exit in (x2, y2). It’s guaranteed that (x1, y1) and (x2, y2) in the map are both empty grid.
     
    Output
    For each case, output a integer indicating the minimal time Bob will use in total to walk between tunnels.
    If it is impossible for Bob to visit all the tunnels, output -1.
     
    Sample Input
    5 4
    ....#
    ...#.
    .....
    .....
    .....
    2 3 1 4
    1 2 3 5
    2 3 3 1
    5 4 2 1
     
    Sample Output
    7
     
    题目大意:在一张nxn(n<16)的图中,"."表示空白区域,"#"表示障碍,每次移动的方向是上下左右之一,每移动一次耗时加1。有m条已知进口和出口的隧道,在隧道中移动不花时间。问要游览完所有的隧道最少需要的时间是多少?顺序自选。
    题目分析:一看数据规模那么小,就想到是状压DP了。但要用BFS预处理出两两隧道之间的距离(起始隧道的出口与终止隧道的进口的距离)。定义状态dp(i,j)表示已经走过的隧道集合为i,并且当前在j位置时已经花掉的最小时间。则状态转移方程为dp(i|(1<<k),k)=min(dp(i|(1<<k),k),dp(i,j)+dist(j,k))。
     
     
    代码如下:
    # include<iostream>
    # include<cstdio>
    # include<queue>
    # include<cstring>
    # include<algorithm>
    using namespace std;
    const int INF=100000;
    struct TT
    {
        int sx,sy,ex,ey;
    };
    struct node
    {
        int x,y,t;
        node(int _x,int _y,int _t):x(_x),y(_y),t(_t){}
    };
    TT t[15];
    char mp[20][20];
    int dist[20][20];
    int vis[20][20],n,m,dp[1<<15][15];
    int d[4][2]={{0,-1},{0,1},{-1,0},{1,0}};
    int bfs(int sx,int sy,int ex,int ey)
    {
        queue<node>q;
        memset(vis,0,sizeof(vis));
        vis[sx][sy]=1;
        q.push(node(sx,sy,0));
        while(!q.empty())
        {
            node u=q.front();
            q.pop();
            if(u.x==ex&&u.y==ey)
                return u.t;
            for(int i=0;i<4;++i){
                int nx=u.x+d[i][0],ny=u.y+d[i][1];
                if(nx>=1&&nx<=n&&ny>=1&&ny<=n&&!vis[nx][ny]&&mp[nx][ny]!='#'){
                    vis[nx][ny]=1;
                    q.push(node(nx,ny,u.t+1));
                }
            }
        }
        return INF;
    }
    void init()
    {
        for(int i=0;i<m;++i)
            for(int j=0;j<m;++j)
                dist[i][j]=bfs(t[i].ex,t[i].ey,t[j].sx,t[j].sy);
    }
    void DP()
    {
        int tot=1<<m;
        for(int i=0;i<tot;++i)
            for(int j=0;j<m;++j)
                dp[i][j]=INF;
        for(int i=0;i<m;++i)
            dp[1<<i][i]=0;
        for(int i=1;i<tot;++i){
            for(int j=0;j<m;++j){
                if(i&(1<<j))
                    continue;
                int sta=i|(1<<j);
                for(int k=0;k<m;++k){
                    if(i&(1<<k))
                        dp[sta][j]=min(dp[sta][j],dp[i][k]+dist[k][j]);
                }
            }
        }
        int ans=INF;
        for(int i=0;i<m;++i)
            ans=min(ans,dp[tot-1][i]);
        if(ans==INF)
            printf("-1
    ");
        else
            printf("%d
    ",ans);
    }
    int main()
    {
        while(~scanf("%d%d",&n,&m))
        {
            for(int i=1;i<=n;++i)
                scanf("%s",mp[i]+1);
            for(int i=0;i<m;++i)
                scanf("%d%d%d%d",&t[i].sx,&t[i].sy,&t[i].ex,&t[i].ey);
            init();
            DP();
        }
        return 0;
    }
    

      

  • 相关阅读:
    Java中取两位小数
    MySQL的IFNULL函数
    JS计算本周一和本周五的日期
    巅峰,不在一万米的边缘
    一段遍历4X4表格,取出每个单元格内容组合成文本的JS代码
    一个用于发送HTML格式邮件的类
    在Java程序中做字符串拼接时一定要记得的MessageFormat.format
    人就这么一辈子,要做自己想做的事情
    错误: 类Something是公共的, 应在名为 Something.java 的文件中声明
    Java中,权限修饰符的权限测试
  • 原文地址:https://www.cnblogs.com/20143605--pcx/p/4786933.html
Copyright © 2011-2022 走看看