• [HNOI2007]紧急疏散 EVACUATE


    题目链接
    数据范围非常小,一共20*20个点,首先考虑网络流。
    题中的限制条件就是每个出口每一时刻限通过1人,换言之,一共撤离时间为t的话,这个出口最多通过t人。
    求时间的最小值,那么可以考虑二分这个时间t。
    那就可以考虑连边了,显然这个t人就是一个流量限制。建立超级源点S、T,S向每个"."连流量为1的边,每个出口向T连流量为t的边。每个"."向它距离不超过t的出口连流量为1的边。
    只要最大流等于总人数就说明这是个合法解。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<cstdlib>
    #include<vector>
    #include<set>
    #include<map>
    #include<string>
    #include<iostream>
    #include<queue>
    #include<cctype>
    using namespace std;
    
    #define A(x) cout << #x << " " << x << endl;
    #define AA(x,y) cout << #x << " " << x << #y << " " << y << endl;
    #define B cout << "Break" << endl;
    #define ll long long
    
    int read()
    {
    	char c = getchar();
    	int x = 0,f = 1;
    	while(!isdigit(c))
    	{
    		if(c == '-') f = -1;
    		c = getchar();
    	}
    	while(isdigit(c))
    	{
    		x = x * 10 + c - '0';
    		c = getchar();
    	}
    	return f * x;
    }
    #define inf 1000000000
    #define N 100010
    #define M 500010
    int head[N],nxt[M],to[M],val[M];
    int ecnt = 1,tot,a,b;
    void Add(int u,int v,int w)
    {
        nxt[++ecnt] = head[u];
        head[u] = ecnt;
        to[ecnt] = v;
        val[ecnt] = w;
    }
    void add(int u,int v,int w)
    {
        Add(u,v,w);
        Add(v,u,0);
    }
    int s,t;
    int cur[N],dep[N];
    bool bfs()
    {
        queue<int>q;
        while(!q.empty()) q.pop();
        memset(dep,-1,sizeof(dep));
        dep[s] = 0;
        q.push(s);
        while(!q.empty())
        {
            int u = q.front();
            q.pop();
            for(int i = head[u];i;i = nxt[i])
            {
                int v = to[i];
                if(dep[v] == -1 && val[i] > 0)
                {
                    dep[v] = dep[u] + 1;
                    q.push(v);
                }
            }
        }
        return dep[t] != -1;
    }
    int dfs(int u,int flow)
    {
        if(u == t) return flow;
        int used = 0,tmp = 0;
        for(int &i = cur[u];i;i = nxt[i])
        {
            int v = to[i];
            if(dep[v] == dep[u] + 1 && val[i] > 0)
            {
                tmp = dfs(v,min(val[i],flow - used));
                if(tmp > 0)
                {
                    val[i] -= tmp;
                    used += tmp;
                    val[i ^ 1] += tmp;
                    if(used == flow) return used;
                }
            }
        }
        if(used != flow) dep[u] = -1;
        return used;
    }
    int maxflow()
    {
        int tmp,ans = 0;
        while(bfs())
        {
            memcpy(cur,head,sizeof(head));
            while((tmp = dfs(s,inf))) ans += tmp;
        }
        return ans;
    }
    
    void reset()
    {
        memset(head,0,sizeof(head));
        memset(nxt,0,sizeof(nxt));
        memset(to,0,sizeof(to));
        memset(val,0,sizeof(val));
        ecnt = 1;
    }
    char mp[30][30];
    int xx[5] = {0,0,1,-1};
    int yy[5] = {1,-1,0,0};
    struct node
    {
        int x,y;
    };
    vector<node>pot,door;
    int get(int x,int y)
    {
        return b * (x - 1) + y;
    }
    int dis[1010][30][30];
    void Run()
    {
        memset(dis,-1,sizeof(dis));
        queue<node>q;
        for(int i = 0;i < door.size();i++)
        {
            int sx = door[i].x,sy = door[i].y;
            dis[i][sx][sy] = 0;
            while(!q.empty()) q.pop();
            q.push((node){sx,sy});
            while(!q.empty())
            {
                int x = q.front().x,y = q.front().y;
                q.pop();
                for(int j = 0;j < 4;j++)
                {
                    int nx = x + xx[j],ny = y + yy[j];
                    if(nx <= 0 || nx > a || ny <= 0 || ny > b || mp[nx][ny] == 'X' || dis[i][nx][ny] != -1) continue;
                    dis[i][nx][ny] = dis[i][x][y] + 1;
                    q.push((node){nx,ny});
                }
            }
        }
        return;
    }
    bool check(int tim)
    {
        reset();
        for(int i = 0;i < pot.size();i++)
        {
            int x = pot[i].x,y = pot[i].y;
            add(s,get(x,y),1);
        }
        for(int i = 0;i < door.size();i++)
        {
            int x = door[i].x,y = door[i].y;
            add(get(x,y),t,tim);
        }
        for(int i = 0;i < door.size();i++)
        {
            for(int j = 0;j < pot.size();j++)
            {
                int x = pot[j].x,y = pot[j].y;
                if(dis[i][x][y] <= tim && dis[i][x][y] != -1) add(get(x,y),get(door[i].x,door[i].y),1);
            }
        }
        return maxflow() >= (int)pot.size();
    }
    int main()
    {
        memset(mp,0,sizeof(mp));
        scanf("%d %d",&a,&b);
        for(int i = 1;i <= a;i++) scanf("%s",mp[i] + 1);
        pot.clear(),door.clear();
        for(int i = 1;i <= a;i++)
        {
            for(int j = 1;j <= b;j++)
            {
                if(mp[i][j] == '.')
                    pot.push_back((node){i,j});
                else if(mp[i][j] == 'D')
                    door.push_back((node){i,j});
            }
        }
        s = 10001,t = 10002;
        int l = 0,r = a * b + 1;
        Run();
        while(l < r)
        {
            int mid = (l + r) >> 1;
            if(check(mid)) r = mid;
            else l = mid + 1;
        }
        if(l <= a * b) printf("%d
    ",l);
        else puts("impossible");
    }
    
  • 相关阅读:
    线程的休眠和中断
    线程的强制运行
    多线程基础
    jar文件につぃて
    Exception和RuntimeException
    异常的抛出
    java之适配器模式
    分支语句
    运算符与表达式
    练习课(一)
  • 原文地址:https://www.cnblogs.com/lijilai-oi/p/12103780.html
Copyright © 2020-2023  润新知