zoukankan      html  css  js  c++  java
  • hdu 3572 Escape 网络流

    题目链接

    给一个n*m的图, 里面有一些点, '.'代表空地, '#'代表墙, 不可以走, '@'代表大门, 可以有多个, 'X'代表人, 问所有人都走出大门需要的最短时间, 每一时刻一个格子只能有一个人, 每个时刻只能有一个人从大门走出, 如果不能走出, 输出-1。

    先dfs判断是否每个人都能走出, 如果有人不能, 直接输出-1。

    从小到大枚举时间, 对于枚举的时间t, 每个格子i, j向它四周以及他本身建边, ( i*m+j+(t-1)*nm, x*m+y+t*nm, 1), 这样就相当于t-1时刻的点向t时刻的点连了一条边。 然后每个出口向汇点连边, (x*m+y+t*nm, 汇点, 1)。 源点向0时刻的每个人连边, 只连一次。

    这样每次都跑一遍网络流, 如果结果ans等于人数sum, 那么说明这个时刻是最小时刻, 需要注意的是, 如果结果不等于人数, 那么sum -= ans。

    具体看代码。

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define mem(a) memset(a, 0, sizeof(a))
      4 #define mem1(a) memset(a, -1, sizeof(a))
      5 #define mem2(a) memset(a, 0x3f, sizeof(a))
      6 const int inf = 1061109567;
      7 const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1},{0, 0} };
      8 const int maxn = 2e6+5;
      9 int q[maxn*2], head[maxn*2], dis[maxn/10], s, t, m, n, vis[30][30], num, flag, sum;
     10 char c[30][30];
     11 struct node
     12 {
     13     int to, nextt, c;
     14     node(){}
     15     node(int to, int nextt, int c):to(to), nextt(nextt), c(c){}
     16 }e[maxn*2];
     17 void init() {
     18     num = flag = sum = 0;
     19     mem1(head);
     20 }
     21 void add(int u, int v, int c) {
     22     e[num] = node(v, head[u], c); head[u] = num++;
     23     e[num] = node(u, head[v], 0); head[v] = num++;
     24 }
     25 int bfs() {
     26     mem(dis);
     27     dis[s] = 1;
     28     int st = 0, ed = 0;
     29     q[ed++] = s;
     30     while(st<ed) {
     31         int u = q[st++];
     32         for(int i = head[u]; ~i; i = e[i].nextt) {
     33             int v = e[i].to;
     34             if(!dis[v]&&e[i].c) {
     35                 dis[v] = dis[u]+1;
     36                 if(v == t)
     37                     return 1;
     38                 q[ed++] = v;
     39             }
     40         }
     41     }
     42     return 0;
     43 }
     44 int dfs(int u, int limit) {
     45     if(u == t) {
     46         return limit;
     47     }
     48     int cost = 0;
     49     for(int i = head[u]; ~i; i = e[i].nextt) {
     50         int v = e[i].to;
     51         if(e[i].c&&dis[v] == dis[u]+1) {
     52             int tmp = dfs(v, min(limit-cost, e[i].c));
     53             if(tmp>0) {
     54                 e[i].c -= tmp;
     55                 e[i^1].c += tmp;
     56                 cost += tmp;
     57                 if(cost == limit)
     58                     break;
     59             } else {
     60                 dis[v] = -1;
     61             }
     62         }
     63     }
     64     return cost;
     65 }
     66 int dinic() {
     67     int ans = 0;
     68     while(bfs()) {
     69         ans += dfs(s, inf);
     70     }
     71     return ans;
     72 }
     73 // 上面是模板
     74 int judge(int x, int y) {
     75     if(x>=0&&x<n&&y>=0&&y<m&&c[x][y]!='#'&&!vis[x][y])
     76         return 1;
     77     return 0;
     78 }
     79 
     80 int dfs1(int x, int y) {
     81     for(int i = 0; i<4; i++) {
     82         int tmpx = x+dir[i][0];
     83         int tmpy = y+dir[i][1];         //判断能否走出
     84         if(judge(tmpx, tmpy)) {
     85             if(c[tmpx][tmpy]=='@')
     86                 return 1;
     87             vis[tmpx][tmpy] = 1;
     88             if(dfs1(tmpx, tmpy))
     89                 return 1;
     90         }
     91     }
     92     return 0;
     93 }
     94 
     95 int ok(int deep) {          //枚举时间, 每一次枚举, 都在原有的图的基础上继续建边,因为原图已经跑过一遍最大流, 所以每次结束后
     96     int nm = n*m;           //总人数都应该减去每一次的结果, 意思是已经有那么多的人跑了出去。
     97     for(int i = 0; i<n; i++) {
     98         for(int j = 0; j<m; j++) {
     99             if(c[i][j] == '@') {
    100                 add(i*m+j+nm*deep+2, t, 1);     //对于每一时刻, 出口都要向汇点建边。
    101                 continue;
    102             }
    103             if(c[i][j]=='#')
    104                 continue;
    105             for(int k = 0; k<5; k++) {
    106                 int x = i+dir[k][0];
    107                 int y = j+dir[k][1];
    108                 if(judge(x, y)) {
    109                     add(i*m+j+(deep-1)*nm+2, x*m+y+deep*nm+2, 1);       //前一时刻的点向这一时刻建边。
    110                 }
    111             }
    112         }
    113     }
    114     int ans = dinic();
    115     if(ans == sum)
    116         return 1;
    117     sum -= ans;         //这里十分重要啊....
    118     return 0;
    119 }
    120 
    121 int main()
    122 {
    123     while(~scanf("%d%d", &n, &m)) {
    124         init();
    125         for(int i = 0; i<n; i++)
    126             scanf("%s", c[i]);
    127         s = 0, t = 1;
    128         for(int i = 0; i<n; i++) {
    129             for(int j = 0; j<m; j++) {
    130                 if(c[i][j] == 'X') {
    131                     add(s, i*m+j+2, 1);             //源点向0时刻的每一个人连边
    132                     mem(vis);
    133                     sum++;
    134                     if(!dfs1(i, j)) {
    135                         flag = 1;
    136                     }
    137                 }
    138             }
    139         }
    140         if(flag) {
    141             puts("-1");
    142             continue;
    143         }
    144         mem(vis);
    145         int ans;
    146         for(ans = 1; ; ans++) {
    147             if(ok(ans))                 //枚举时间
    148                 break;
    149         }
    150         cout<<ans<<endl;
    151     }
    152 }
  • 相关阅读:
    SVN中trunk、branches、tag的使用
    svn建立分支和svn代码合并的操作方法
    SVN分支的合并和同步
    iOS开发--即时通讯
    iOS 开发--开源图片处理圆角
    ios开发--网易滚动导航栏
    ios开发--高德地图SDK使用简介
    大型网站架构演变和知识体系
    Nginx配置文件nginx.conf中文详解
    nginx+apache+php+mysql服务器集群搭建
  • 原文地址:https://www.cnblogs.com/yohaha/p/5032053.html
Copyright © 2011-2022 走看看