POJ 3057 Evacuation

分析

这是一个时间和门的二元组(t,d)和人p匹配的问题,当我们固定d0时,(t,d0)匹配的人数和t具有单调性。

t增加看成是多增加了边就行了,所以bfs处理出p到每个d的最短时间,然后把(t,d)和p连边,按t从小到大

枚举点增广就好了。无解的情况只有一种,某个人无论如何都无法出去。

/*********************************************************
*      --Sakura hirahira mai orite ochite--              *
*   author AbyssalFish                                   *
**********************************************************/
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<queue>
#include<vector>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
#include<cmath>
using namespace std;

typedef long long ll;

const int XY = 12, MAX_D = 44, MAX_P = 100;//..MAX_T
char maz[XY][XY+1];

const int maxv = MAX_D*MAX_P, maxe = maxv*MAX_P;
int hd[maxv],to[maxe],nx[maxe],ec;
#define eachEage int i = hd[u]; ~i; i = nx[i]
void add(int u,int v)
{
    nx[ec] = hd[u];
    to[ec] = v;
    hd[u] = ec++;
}

#define PB push_back
#define resv(x,n) x.reserve(n);
#define PS push
vector<int> pX, pY, dX, dY;

const int dx[] = {0,0,-1,1}, dy[] = {1,-1,0,0};

int dist[XY][XY][XY][XY];
int X,Y;

void bfs(int x,int y)
{
    int (* const d)[XY] = dist[x][y];
    memset(d,0xff,sizeof(dist[x][y]));

    queue<int> qx, qy;
    d[x][y] = 0;
    qx.PS(x); qy.PS(y);
    while(qx.size()){
        x = qx.front(); qx.pop();
        y = qy.front(); qy.pop();
        for(int k = 4; k--;){
            int nx = x+dx[k], ny = y+dy[k];
            if(0<=nx && nx<X && 0<=ny && ny<Y && maz[nx][ny] == ‘.‘ && d[nx][ny]<0){
                d[nx][ny] = d[x][y]+1;
                qx.PS(nx); qy.PS(ny);
            }
        }
    }
}

int link[MAX_P];
int vis[maxv], clk;

bool aug(int u)
{
    vis[u] = clk;
    for(eachEage){
        int v = to[i], w = link[v];
        if(w<0 || (vis[w] != clk && aug(w))){
            link[v] = u;
            return true;
        }
    }
    return false;
}

//#define LOCAL
int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif
    resv(pX,MAX_P) resv(pX,MAX_P) resv(dX,MAX_D) resv(dY,MAX_D)
    int T; cin>>T;
    while(T--){
        scanf("%d%d",&X,&Y);
        pX.clear(); pY.clear();
        dX.clear(); dY.clear();
        for(int i = 0; i < X; i++){
            scanf("%s", maz[i]);
            for(int j = 0; j < Y; j++){
                if(maz[i][j] == ‘D‘){
                    dX.PB(i); dY.PB(j);
                }
                else if(maz[i][j] == ‘.‘){
                    pX.PB(i); pY.PB(j);
                }
            }
        }
        int d = dX.size(), p = pX.size();
        if(p == 0){ puts("0"); continue; }
        for(int i = 0; i < d; i++){
            bfs(dX[i],dY[i]);
        }
        int n = (X-2)*(Y-2);
        bool fail = false;
        memset(hd,0xff,sizeof(int)*n*d); ec = 0;
        for(int i = 0; i < p; i++){
            bool escape = false;
            for(int j = 0; j < d; j++){
                if(dist[dX[j]][dY[j]][pX[i]][pY[i]] > 0){
                    if(!escape) escape = true;
                    for(int k = dist[dX[j]][dY[j]][pX[i]][pY[i]]-1; k < n; k++){
                        add(k*d+j, i);
                    }
                }
            }
            if(!escape){
                fail = true; break;
            }
        }
        if(fail){ puts("impossible"); continue; }
        memset(link,-1,sizeof(int)*p);
        int cnt = 0, ans;
        for(int i = 0; i < n*d; i++){
            clk++;
            if(aug(i) && ++cnt == p) {
                ans = i/d+1;
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}
时间: 2024-08-06 07:50:38

POJ 3057 Evacuation的相关文章

POJ 3057 Evacuation 二分图匹配

每个门每个时间只能出一个人,那就把每个门拆成多个,对应每个时间. 不断增加时间,然后增广,直到最大匹配. //#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<iostream> #include<

POJ 2175 Evacuation Plan 费用流 负圈定理

题目给了一个满足最大流的残量网络,判断是否费用最小. 如果残量网络中存在费用负圈,那么不是最优,在这个圈上增广,增广1的流量就行了. 1.SPFA中某个点入队超过n次,说明存在负环,但是这个点不一定在负环上. 2.这个负环可能包括汇点t,所以构建残量网络的时候也要考虑防空洞到t上的容量. //#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring

POJ 3057 网络流 Evacuation

题意: 有一个n×m的房间,四周每个格子要么是墙要么是门.中间部分是墙或者人. 现在所有人要从房间逃出去,每个人的速度为1,也就是每个单位时间只能向上下左右四个方向走一格. 多个人可以站在同一个格子上,但是每个时刻每个门只能通过一格人,求所有人从房间中逃出去所需要的最少时间. 分析: 把每个人看成一个点,然后把每个时刻和门组成的二元组看成一个点. 如果两点之间连一条边表示这个人在这个时刻从这个门逃出去. 所以我们可以从小到大将时间逐渐加1,直到找到最大匹配为止. 在增加点的时候,可以在之前最大流

POJ 2175 Evacuation Plan (费用流,负环,消圈法,SPFA)

http://poj.org/problem?id=2175 Evacuation Plan Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3256   Accepted: 855   Special Judge Description The City has a number of municipal buildings and a number of fallout shelters that were build

POJ 2175 Evacuation Plan

Evacuation Plan Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged on PKU. Original ID: 217564-bit integer IO format: %lld      Java class name: Main The City has a number of municipal buildings and a number of fallout shelters that

POJ.2175.Evacuation Plan(消圈)

POJ \(Description\) \(n\)个建筑物,每个建筑物里有\(a_i\)个人:\(m\)个避难所,每个避难所可以容纳\(b_i\)个人. 给出每个建筑物及避难所的坐标,任意两点间的距离为它们的曼哈顿距离\(+1\). 现在给出一个分配方案(\(g[i][j]\)表示第\(i\)个建筑物去第\(j\)个避难所的人数),问是否存在所有人移动的距离之和比当前更小的方案.如果存在,输出任意一组更小的方案. \(n,m\leq100\) \(Solution\) 直接跑费用流会T,但是也没

POJ 2175 Evacuation Plan 费用流消圈

题目大意:给出一个费用流的模型和已经流过的一些边,问是否存在比这个解更优的解. 思路:直接用原图做一次费用流求最优解会T掉.先介绍费用流消圈定理:如果当前费用流的残量网络中存在负圈,那么当前流不是最优的解. 其实很好理解,结合原图和流过流量之后的反边,若出现了负圈,那么就可以沿着这个负圈增广,而且费用更小. 不过为了解决这个题我们并不需要建立完整的网络流,只需要建立残量网络之后SPFA看是否能找到负环即可. 具体建立方法: 如果一个避难地点有值,那么T向这个避难地点连边,费用0 若当前避难地点没

POJ - 2175 Evacuation Plan (最小费用流消圈)

题意:有N栋楼,每栋楼有\(val_i\)个人要避难,现在有M个避难所,每个避难所的容量为\(cap_i\),每个人从楼i到避难所j的话费是两者的曼哈顿距离.现在给出解决方案,问这个解决方案是否是花费最小的,若不是,则给出比这个更优的解. 分析:若只是要我们求一个最优解的话就用费用流做.现在要求判断是否最优,那么就是当前这张图中是否最短路还能被更新. 首先需要根据给定的解决方案重现这个状态下的残余网,其实只需要加入必要的弧即可:对与任意的楼与避难所(i,j),建边,费用为其距离;若i->j有流量

图论常用算法之一 POJ图论题集【转载】

POJ图论分类[转] 一个很不错的图论分类,非常感谢原版的作者!!!在这里分享给大家,爱好图论的ACMer不寂寞了... (很抱歉没有找到此题集整理的原创作者,感谢知情的朋友给个原创链接) POJ:http://poj.org/ 1062* 昂贵的聘礼 枚举等级限制+dijkstra 1087* A Plug for UNIX 2分匹配 1094 Sorting It All Out floyd 或 拓扑 1112* Team Them Up! 2分图染色+DP 1125 Stockbroker