[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\n",l);
    else puts("impossible");
}
posted @ 2019-12-26 18:39  锦依卫Lijilai  阅读(116)  评论(0编辑  收藏  举报