zoukankan      html  css  js  c++  java
  • [BZOJ1189][P3191][HNOI2007]紧急疏散evacuate[最大流+二分答案]

    对每个门bfs,求出每个点到这个门需要的时间

    二分答案,每次建图的时候在当前时间内能到达就连边,不能到达就不连边

    我好像做麻烦了,不需要拆点,直接这样建图就行:

    S到空地连一条容量1的边,每个空地到可到达的门连一条容量1的边,每个门到T连一条容量为时间的边

    #include <bits/stdc++.h>
    using namespace std;
    const int inf = 0x3f3f3f3f;
    const int MAXN = 81007;
    int n, m, s, t, dep[MAXN], maxflow, dis[25][25], N;
    bool vis[25][25];
    #define Get(i, j) ((i-1) * m + j)
    char mat[25][25];
    struct Edge {
      int v, w, next;
    } G[MAXN<<2];
    int tot = 1, head[MAXN], cur[MAXN], peo;
    inline void add(int u, int v, int w) {
      G[++tot] = (Edge) {v, w, head[u]};head[u] = tot;
      G[++tot] = (Edge) {u, 0, head[v]};head[v] = tot;
    }
    inline bool bfs(int s, int t) {
      memset(dep, 0x7f, sizeof dep);
      memcpy(cur+1, head+1, sizeof(head)-4);
      queue<int>q;
      while(!q.empty()) q.pop();
      dep[s] = 0;
      q.push(s);
      while(!q.empty()) {
        int u = q.front();
        q.pop();
        for(int i = head[u]; i; i = G[i].next) {
          int v = G[i].v, w = G[i].w;
          if (dep[v] > inf && w) {
            dep[v] = dep[u] + 1;
            if (v == t) return 1;
            q.push(v);
          }
        }
      }
      return dep[t] < inf;
    }
     
    int dfs(int u, int t, int limit) {
      if (u == t || !limit) return limit;
      int flow = 0, f;
      for(int i = cur[u]; i; i = G[i].next) {
        cur[u] = i;
        int v = G[i].v, w = G[i].w;
        if (dep[v] == dep[u] + 1 && (f = dfs(v, t, min(w, limit)))) {
          flow += f;
          limit -= f;
          G[i].w -= f;
          G[i^1].w += f;
          if (!limit) break;
        }
      }
      return flow;
    }
     
    void dinic(int s, int t) {
      while(bfs(s, t)) maxflow += dfs(s, t, inf);
    }
    int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};
    void BFS(int sx, int sy, int step) {
      queue<int>q;
      q.push(sx), q.push(sy);
      memset(dis, 0x3f, sizeof dis);
      dis[sx][sy] = 0;
      while(!q.empty()) {
        int x = q.front();q.pop();int y = q.front(); q.pop();
        if (dis[x][y] >= step) break;
        for(int i = 0; i < 4; ++i) {
          int xx = x + dx[i], yy = y + dy[i];
          if (mat[xx][yy] == 'X' || !(xx >= 1 && xx <= n && yy >= 1 && yy <= m) || dis[xx][yy] != inf) continue; 
          dis[xx][yy] = dis[x][y] + 1;
          add(Get(sx, sy), Get(xx, yy) + 800 + dis[xx][yy] * N, 1);
          if (mat[xx][yy] == '.') q.push(xx), q.push(yy);
        }
      }
    }
    inline bool check(int tim) {
      memset(head, 0, sizeof head), tot = 1, maxflow = 0;
      for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= m; ++j) {
          if (mat[i][j] == '.') add(s, Get(i, j), 1), BFS(i, j, tim);
          else if (mat[i][j] == 'D') {
            for(int k = 1; k < tim; ++k) add(800 + k * N + Get(i, j), 800 + (k+1) * N + Get(i, j), inf), add(800 + k * N + Get(i, j), t, 1);
            add(800 + tim * N + Get(i, j), t, 1);
          }
        }
      dinic(s, t);
      return maxflow == peo;
    }
    int main(void) {
      scanf("%d %d", &n, &m);
      for(int i = 1; i <= n; ++i) scanf("%s", mat[i]+1);
      for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) peo += mat[i][j] == '.';
      int l = 1, r = 201, ans = -1;
      s = 70000, t = 70001, N = Get(n, m);
      while(l <= r) {
        int mid = l+r>>1;
        if (check(mid)) r = mid-1, ans = mid;
        else l = mid+1;
      }
      if (ans == -1) puts("impossible");
      else cout << l;
      return 0;
    }
    
    
  • 相关阅读:
    【从0开始Tornado网站】主页登录和显示的最新文章
    2014阿里巴巴网上笔试题-文章3大标题-公共最长的字符串长度
    取消改变基本数据——应用备忘录模式
    Hibernate进化史-------Hibernate概要
    xcode 快捷键
    Android多画面幻灯片:ViewPager基础上,利用与PagerTabStrip出生缺陷(源代码)
    uva 11991
    创建与删除索引
    HDU1203_I NEED A OFFER!【01背包】
    Java面试宝典2013版(超长版)
  • 原文地址:https://www.cnblogs.com/storz/p/10191291.html
Copyright © 2011-2022 走看看