zoukankan      html  css  js  c++  java
  • hdu 2732 Leapin' Lizards(最大流)Mid-Central USA 2005

    废话:

    这道题不难,稍微构造一下图就可以套最大流的模板了。但是我还是花了好久才解决。一方面是最近确实非常没状态(托词,其实就是最近特别颓废,整天玩游戏看小说,没法静下心来学习),另一方面是不够细心,输出格式错了大意没有发现死一只和死多只之间的区别,卡在那里动不了。

    题意:

    在一张n*m的地图中,有一群蜥蜴,这群蜥蜴每次可以跳跃曼哈顿距离d(曼哈顿距离——dis(a, b) = |ax-bx|+|ay-by|,之后所有的距离都是曼哈顿距离),这些蜥蜴只能在地图上的一些柱子上跳跃。柱子i最多可以支持ki次经过。如果柱子i距离地图的边界的距离小于d那么蜥蜴可以从柱子i逃出升天。要求计算最后会有多少蜥蜴葬身图中。

    输入:

    第一行输入一个整数t,表示共有t组数据。

    第二行输入两个整数nd,表示这组数据中地图有n行,蜥蜴一次最大跳跃距离d

    接下来n行输入地图mp1,地图中的数字表示柱子可以经过的次数,0表示不可以经过。

    接下来n行输入地图mp2,其中’.’表示空,’L’表示存在一只蜥蜴。

    输出:

    首先输出组数”Case #x: “,其中x表示第x组。

    如果所有的蜥蜴都可以逃出,那么输出”no lizard was left behind.”

    如果只有1只死去,那么输出”1 lizard was left behind.”

    如果死去多于1只,那么输出”y lizards were left behind.”y表示死去的蜥蜴数量。

    题解:

    经过一番变化,我们可以构造出一张有向图,然后使用最大流来解决这个问题。

    构造方法如下——

    1. 我们设源点为0,汇点为2*n*m+1(其中n为地图的行,m为地图的列),设图中两点p1p2的距离,即p1p2的有向边为mp[p1][p2]
    2. 将地图mp1中所有的点拆分成两个点,点pij拆分为mp[][]中的点i*m+j+1n*m+i*m+j+1,添加边mp[i*m+j+1][n*m+i*m+j+1] = mp1[i][j]。这是我们构造图mp中最关键的一步,正是因为有了这个有向边,我们才可以使用最大流来计算这个题。
    3. 对于地图mp1,枚举每个点pij,如果这个点距离地图边界的距离小于等于d,那么添加边mp[n*m+i*m+j+1][2*m*n+1] = mp1[i][j];同时枚举除pij以外的点pkl,如果pijpkl之间的距离小于等于d那么添加边mp[n*m+i*m+j+1][k*m+l+1] = max(mp1[i][j], mp1[k][l])
    4. 对于地图mp2,如果某个点pij 的值mp2[i][j] == ‘L’,那么构造边mp[0][i*m+j+1] = 1

    然后计算从源点到汇点的最大流即可,我使用的Dinic算法。

    具体见代码——

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <cmath>
      4 #include <algorithm>
      5 #include <queue>
      6 using namespace std;
      7 
      8 const int N = 1000;
      9 const int M = 100000010;
     10 
     11 int dis[N];
     12 int cur[N];
     13 bool vis[N];
     14 char mp[2][30][30];
     15 int mp2[N][N];
     16 int n, m, d, t;
     17 int ans, sum;
     18 
     19 inline int Min(int x, int y)
     20 {
     21     return x < y ? x : y;
     22 }
     23 
     24 void init()
     25 {
     26     memset(mp, 0, sizeof(mp));
     27     memset(mp2, 0, sizeof(mp2));
     28     scanf("%d%d", &n, &d);
     29     scanf("%s", mp[0][0]);
     30     m = strlen(mp[0][0]);
     31     sum = 0;
     32     ans = 0;
     33     for(int i = 1; i < n; i++)
     34     {
     35         scanf("%s", mp[0][i]);
     36     }
     37     for(int i = 0; i < n; i++)
     38     {
     39         for(int j = 0; j < m; j++)
     40         {
     41             for(int k = 0; k < n; k++)
     42             {
     43                 for(int l = 0; l < m; l++)
     44                 {
     45                     int mid1 = abs(i-k)+abs(j-l);
     46                     if(mid1 <= d && i*m+j+1 != k*m+l+1)         //点pij到点pkl之间距离小于等于d且不是同一点
     47                     {
     48                         int mid = Min(mp[0][i][j], mp[0][k][l]);
     49                         mp2[n*m+i*m+j+1][k*m+l+1] = mid;        //从点pij到点pkl的边
     50                     }
     51                 }
     52             }
     53             mp2[i*m+j+1][n*m+i*m+j+1] = mp[0][i][j]-'0';        //从点pij到点pij的边
     54             if(i < d || j < d || n-i <= d || m-j <= d) mp2[m*n+i*m+j+1][2*n*m+1] = mp[0][i][j]-'0';     //从点pij到汇点的边
     55         }
     56     }
     57     for(int i = 0; i < n; i++)
     58     {
     59         scanf("%s", mp[1][i]);
     60         for(int j = 0; j < m; j++)
     61         {
     62             if(mp[1][i][j] == 'L')
     63             {
     64                 mp2[0][i*m+j+1] = 1;                            //从源点到点pij的边
     65                 sum++;
     66             }
     67         }
     68     }
     69     m = 2*n*m+1;
     70 }
     71 
     72 bool bfs()
     73 {
     74     memset(vis, 0, sizeof(vis));
     75     queue<int> que;
     76     que.push(0);
     77     dis[0] = 0;
     78     vis[0] = 1;
     79     while(!que.empty())
     80     {
     81         int k = que.front();
     82         que.pop();
     83         for(int i = 0; i <= m; i++)
     84         {
     85             if(!vis[i] && mp2[k][i] > 0)
     86             {
     87                 vis[i] = 1;
     88                 dis[i] = dis[k]+1;
     89                 que.push(i);
     90             }
     91         }
     92     }
     93     return vis[m];
     94 }
     95 
     96 int dfs(int x, int val)
     97 {
     98     if(x == m || val == 0) return val;
     99     int flow = 0, minn;
    100     for(int& i = cur[x]; i <= m; i++)
    101     {
    102         if(dis[x]+1 == dis[i] && (minn = dfs(i, Min(val, mp2[x][i]))) > 0)
    103         {
    104             mp2[x][i] -= minn;
    105             mp2[i][x] += minn;
    106             flow += minn;
    107             val -= minn;
    108             if(val == 0) break;
    109         }
    110     }
    111     return flow;
    112 }
    113 
    114 void work()                                                 //Dinic算法
    115 {
    116     while(bfs())
    117     {
    118         for(int i = 0; i <= m; i++) cur[i] = 1;
    119         ans += dfs(0, M);
    120     }
    121 }
    122 
    123 void outit(int tm)
    124 {
    125     sum -= ans;
    126     printf("Case #%d: ", tm);
    127     if(!sum) printf("no lizard was left behind.
    ");
    128     else if(sum == 1) printf("1 lizard was left behind.
    ");
    129     else printf("%d lizards were left behind.
    ", sum);
    130 }
    131 
    132 int main()
    133 {
    134     //freopen("test.in", "r", stdin);
    135     scanf("%d", &t);
    136     for(int tm = 1; tm <= t; tm++)
    137     {
    138         init();
    139         work();
    140         outit(tm);
    141     }
    142     return 0;
    143 }
    View Code

    最大流入门——

     http://www.cnblogs.com/mypride/p/4859453.html

  • 相关阅读:
    钞票与选票之争
    poj1066--Treasure Hunt(规范相交)
    mmc生产任务分配问题
    Linux学习杂记
    UVA 10026 Shoemaker&#39;s Problem
    【12c】root container 和 pdb 的一些差别
    Configuring HDFS High Availability
    字符串替换
    一张图搞懂分布式大型站点的前世今生
    HDU1874畅通project续 dijkstra&amp;&amp;floyd
  • 原文地址:https://www.cnblogs.com/mypride/p/4945949.html
Copyright © 2011-2022 走看看