• 【BZOJ 1189】[HNOI2007]紧急疏散evacuate


    【链接】 我是链接,点我呀:)
    【题意】

    在这里输入题意

    【题解】

    二分+网络流

    先处理出所有的人到所有的门的最短路dis(x,y)

    二分所用的时间mid
    则把所有的门都分成mid个。
    表示1..mid这些时间这个门可以通过一个人。
    然后建立一个超级源点S
    S和所有的人各连一条边,边权为1
    然后如果人x能到达门y的话
    那么从x连mid-dis[x,y]+1条边分别至门的第dis[x,y]个点,第dix[x,y]+1个点....第mid个点(每个点各一条,刚好mid-dis[x][y]+1条。
    表示这些时间段这个人都能到达这个点。
    然后所有的门都向超级汇点连一条边。
    这样可以保证,每个门,每个时刻只有一个人经过
    每次跑个最大流
    看看是不是满流就好。
    (即最大流等于人的个数

    是的话mid尝试减小一点

    【代码】

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 20;
    const int NN = 400;
    const int NNN = 160000;
    const int INF = 0x3f3f3f3f;
    const int dx[4] = {0,0,1,-1};
    const int dy[4] = {1,-1,0,0};
    
    struct abc{
        int from,en,cost,nex;
    };
    
    int n,m,cnt = 1,what[N+10][N+10],now = 0;
    int g[NN+10][NN+10],dis[N+10][N+10],dis1[NNN+NN+10],fir[NNN+NN+10],mi[NNN+NN+10],pre[NNN+NN+10];
    char s[N+10][N+10];
    bool inq[NNN+10];
    vector<abc> edge;
    queue<pair<int,int> > dl;
    queue<int> dl2;
    
    void add_edge(int x,int y,int cost){
        abc temp;
        temp.from = x,temp.en = y,temp.cost = cost,temp.nex = fir[x];
        edge.push_back(temp);
        int tot = edge.size()-1;
        fir[x] = tot;
    }
    
    void bfs(int cur,int x,int y){
        memset(dis,INF,sizeof dis);
        dis[x][y] = 0;
        dl.push(make_pair(x,y));
        while (!dl.empty()){
            pair<int,int> temp = dl.front();
            int xx = temp.first,yy = temp.second;
            dl.pop();
            for (int i = 0;i < 4;i++){
                int tx = xx+dx[i],ty = yy+dy[i];
                if (tx>=1 && tx<=n && ty>=1 && ty<=m){
                    if (s[tx][ty]=='X' || s[tx][ty]=='D') continue;
                    if (dis[tx][ty]>dis[xx][yy]+1){
                        dis[tx][ty] = dis[xx][yy]+1;
                        dl.push(make_pair(tx,ty));
                        g[what[tx][ty]][cur] = dis[tx][ty];
                    }
                }
            }
        }
    }
    
    bool ok(int t){
        memset(fir,255,sizeof fir);edge.clear();
        for (int i = 2;i <= cnt;i++) {
            add_edge(1,i,1);
            add_edge(i,1,0);
        }
        int cur = cnt,tnow = 0;
        for (int i = 1;i <= n;i++)
            for (int j = 1;j <= m;j++)
                if (s[i][j]=='D'){
                    tnow++;
                    int pp = cur;
                    for (int k = 1;k <= t;k++) cur++;
                    for (int k = 2;k <= cnt;k++)
                        if (g[k][tnow]<INF){
                            for (int l = pp+g[k][tnow];l <= cur;l++) {
                                add_edge(k,l,1);
                                add_edge(l,k,0);
                            }
                        }
                }
        cur++;
        for (int i = cnt+1;i <= cur-1;i++) {
                add_edge(i,cur,1);
                add_edge(cur,i,0);
        }
    
        int flow = 0;
        while (1){
            int s = 1,t = cur;
            dis1[s] = 0,inq[s] = 1;
            dl2.push(s);
            memset(pre,255,sizeof pre);
            while (!dl2.empty()){
                int x = dl2.front();
                dl2.pop();
                for (int i = fir[x];i!=-1;i = edge[i].nex){
                    int y = edge[i].en;
                    if (edge[i].cost>0 && pre[y]==-1){
                        pre[y] = i;
                        dl2.push(y);
                    }
                }
            }
            if (pre[t]==-1) break;
            int now = t,temp1 = INF;
            while (now != s){
                int temp = pre[now];
                temp1 = min(temp1,edge[temp].cost);
                now = edge[temp].from;
            }
            now = t;
            while (now!=s){
                int temp = pre[now];
                edge[temp].cost-=temp1;
                edge[temp^1].cost+=temp1;
                now = edge[temp].from;
            }
            flow+=now;
        }
        if (flow==cnt-1) return true;
        else return false;
    }
    
    int main(){
        //freopen("D:\rush.txt","r",stdin);
        scanf("%d%d",&n,&m);
        for (int i = 1;i <= n;i++) scanf("%s",s[i]+1);
        for (int i = 1;i <= n;i++)
            for (int j = 1;j <= m;j++)
                if (s[i][j]=='.'){
                    cnt++;
                    what[i][j] = cnt;
                }
    
        memset(g,INF,sizeof g);
        for (int i = 1;i <= n;i++)
            for (int j = 1;j <= m;j++)
                if (s[i][j]=='D'){
                    bfs(++now,i,j);
                }
    
    
        int l = 1,r = n*m,temp = -1;
        while (l <= r){
            int m = (l+r)>>1;
            if (ok(m)){
                temp = m;
                r = m - 1;
            }else l = m + 1;
        }
        if (temp==-1){
            printf("impossible
    ");
        }else{
            printf("%d
    ",temp);
        }
        return 0;
    }
    
    
  • 相关阅读:
    poj 2109Power of Cryptography
    poj 2632Crashing Robots
    poj 2586Y2K Accounting Bug
    linux0.12中文件系统的一些理解
    latex初学者的经验
    关于linux0.12中的add_entry中bread中的些猜测
    uid gid euid egid详解
    关于linux0.12文件系统目录大小的一个发现
    我的初级muttrc配置
    使用STM32的USB模块中后对USB缓冲区的认识
  • 原文地址:https://www.cnblogs.com/AWCXV/p/8716114.html
Copyright © 2020-2023  润新知