• 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

  • 相关阅读:
    UVa 1349 (二分图最小权完美匹配) Optimal Bus Route Design
    UVa 1658 (拆点法 最小费用流) Admiral
    UVa 11082 (网络流建模) Matrix Decompressing
    UVa 753 (二分图最大匹配) A Plug for UNIX
    UVa 1451 (数形结合 单调栈) Average
    UVa 1471 (LIS变形) Defense Lines
    UVa 11572 (滑动窗口) Unique Snowflakes
    UVa 1606 (极角排序) Amphiphilic Carbon Molecules
    UVa 11054 Wine trading in Gergovia
    UVa 140 (枚举排列) Bandwidth
  • 原文地址:https://www.cnblogs.com/mypride/p/4945949.html
Copyright © 2020-2023  润新知