• [HNOI 2007] 紧急疏散


    [题目链接]

             https://www.lydsy.com/JudgeOnline/problem.php?id=1189

    [算法]

              首先 , 答案具有单调性 , 不妨二分答案” 第mid秒是否可以完成疏散 ”

              检验时 , 首先通过广度优先搜索BFS求出每扇门到每个空地的距离

              然后建图 , 判断最大流是否等于空地的数量

              详见代码

              时间复杂度: O(dinic(N ^ 3 , N ^ 3) log N ^ 2)

    [代码]

            

    #include<bits/stdc++.h>
    using namespace std;
    #define MAXN 16100
    #define MAXD 25
    const int inf = 2e9;
    const int dx[4] = {0 , 0 , -1 , 1};
    const int dy[4] = {-1 , 1 , 0 , 0};
    
    struct edge
    {
            int to , w , nxt;
    } e[MAXN << 1];
    
    int tot , cntk , cntd , S , T , n , m;
    int head[MAXN] , depth[MAXN];
    int point[MAXD][MAXD];
    int dist[MAXN][MAXD][MAXD];
    char mp[MAXD][MAXD];
    pair<int , int> a[MAXN * MAXD];
    
    template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
    template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
    template <typename T> inline void read(T &x)
    {
        T f = 1; x = 0;
        char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
        for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
        x *= f;
    }
    inline void addedge(int u , int v , int w)
    {
            ++tot;
            e[tot] = (edge){v , w , head[u]};
            head[u] = tot;
            ++tot;
            e[tot] = (edge){u , 0 , head[v]};
            head[v] = tot;
    }
    inline bool valid(int x , int y)
    {
            return x >= 1 && x <= n && y >= 1 && y <= m;
    }
    inline void do_bfs(int s)
    {
            queue< pair<int , int> > q; 
            q.push(make_pair(a[s].first , a[s].second));
            memset(dist[s] , 0x3f , sizeof(dist[s]));
            dist[s][a[s].first][a[s].second] = 0;        
            while (!q.empty())
            {
                    pair<int , int> cur = q.front();
                    q.pop();
                    for (int i = 0; i < 4; i++)
                    {
                            int nx = cur.first + dx[i] , ny = cur.second + dy[i];
                            if (valid(nx , ny) && mp[nx][ny] == '.')
                            {
                                    if (dist[s][cur.first][cur.second] + 1 < dist[s][nx][ny])
                                    {
                                            dist[s][nx][ny] = dist[s][cur.first][cur.second] + 1;
                                            q.push(make_pair(nx , ny));
                                    }
                            }
                    }
            }
    }     
    inline bool bfs()
    {
            int l , r;
            static int q[MAXN];
            q[l = r = 1] = S;
            memset(depth , 0 ,sizeof(depth));
            depth[S] = 1;
            while (l <= r)
            {
                    int cur = q[l++];
                    for (int i = head[cur]; i; i = e[i].nxt)
                    {
                            int v = e[i].to , w = e[i].w;
                            if (w > 0 && !depth[v])
                            {
                                    depth[v] = depth[cur] + 1;
                                    q[++r] = v;
                                    if (v == T) return true;
                            }
                    }
            }
            return false;
    }
    inline int dinic(int u , int flow)
    {
            int rest = flow , ret = 0;
            if (u == T) return flow;
            for (int i = head[u]; i && rest; i = e[i].nxt)
            {
                    int v = e[i].to , w = e[i].w;
                    if (depth[v] == depth[u] + 1 && w)
                    {
                            int k = dinic(v , min(rest , w));
                            if (!k) depth[v] = 0;    
                            e[i].w -= k;
                            e[i ^ 1].w += k;
                            rest -= k;
                    }    
            }        
            return flow - rest;
    }
    inline bool check(int mid)
    {
            S = cntk + cntd * mid + cntd + 1;
            T = S + 1;
            tot = 0;
            for (int i = 1; i <= T; i++) head[i] = 0;
            for (int i = 1; i <= n; i++)
            {
                    for (int j = 1; j <= m; j++)
                    {
                            if (mp[i][j] == '.')
                                    addedge(S , point[i][j] , 1);
                    } 
            }
            for (int i = 1; i <= cntd; i++) 
            {
                    for (int j = 1; j <= n; j++)
                    {
                            for (int k = 1; k <= m; k++)
                            {
                                    if (mp[j][k] == '.' && dist[i][j][k] <= mid)
                                            addedge(point[j][k] , cntk + (i - 1) * mid + dist[i][j][k] , 1);
                            }
                    }
            }
            for (int i = 1; i <= cntd; i++)
            {
                    for (int j = 1; j <= mid; j++)
                    {
                          addedge(cntk + (i - 1) * mid + j , cntk + cntd * mid + i , mid - j + 1);
                    }
            }
            for (int i = 1; i <= cntd; i++) addedge(cntk + cntd * mid + i , T , mid);
            int ret = 0;
            while (bfs())
            {
                    while (int flow = dinic(S , inf)) ret += flow;        
            } 
            return ret == cntk;
    }
    
    int main()
    {
            
            scanf("%d%d" , &n , &m);
            for (int i = 1; i <= n; i++) scanf("%s" , mp[i] + 1);
            for (int i = 1; i <= n; i++)
            {
                    for (int j = 1; j <= m; j++)
                    {
                            if (mp[i][j] == '.')
                                    point[i][j] = ++cntk;
                            if (mp[i][j] == 'D') a[++cntd] = make_pair(i , j);
                    }
            }
            for (int i = 1; i <= cntd; i++) do_bfs(i);
            int l = 0 , r = n * m , ans = -1;
            while (l <= r)
            {
                    int mid = (l + r) >> 1;
                    if (check(mid))
                    {
                            ans = mid;
                            r = mid - 1;        
                    }    else l = mid + 1;
            }
            if (ans >= 0) printf("%d
    " , ans);
            else printf("impossible
    ");
            
            return 0;
        
    }
  • 相关阅读:
    Android深度探索第一章读书笔记
    ocRuntime基本功
    关于堆栈和block之我见
    OC 与 swift 混编杂记
    UItableViewCell自适应高度的坑
    windows蓝屏处理
    MBProgressHUD自定义customView
    svn 配置忽略文件
    ios 开发项目常用第三方库:
    cocoaPod 更换镜像源
  • 原文地址:https://www.cnblogs.com/evenbao/p/9860759.html
Copyright © 2020-2023  润新知