hdu 1733 网络流 分层网络


Escape

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1385    Accepted Submission(s): 398


Problem Description
Loneknight hates attending class very much. Every time he is attending class, when he feel tiresome with the class, he start planning the shortest path he can escape from the classroom. Therefore, he can escape from classroom so quickly that he is always the first one escape from the classroom after the class finishes. He is very proud of this fact. 

One day, loneknight is day dreaming in class, and planning the shortest path for escaping. Suddently, an issue come into his mind, if everyone in the classroom want to escape as soon as possible just as loneknight, what will happend? As a kind man, loneknight want to plan a strategy that will let everyone escape from the classroom with minimum time consume. But after dozens of minutes of consideration, loneknight find this problem so difficult for him.

Now, as the best friend of him, please design a algorithm to solve this problem for him. Note that, at every time unit, everyone can move seperately up, down, left, right one unit, or stay in the old position. In addtion, no one can move to a wall or out of the room, the only way to escape is go through a gate. Moreover, at every time unit, a position can only contain a person, including gates. That means if in time t, a person escape thourgh gate g, no one can go into g in time t, but can go into g in t + 1. Now, it's your job to calculate the minimum time required to escape for everyone.
 

Input
The input consists of several test cases. Each test case start with a line containing two number, n, m (1 < n, m <= 16), the rows and the columns of the room. Then n lines follow, each contain exact m characters, representing th type of unitin it. (. for empty place, X for human, # for wall, @ for gate). Input is end with EOF.
 

Output
You have to print the shortest time needed for everyone escape from the roomin a single line for each case. (-1 if impossible)
 

Sample Input
  
  
4 4 .@.. .X.. .... .... 4 4 .@.. .XX. .XX. ..@. 4 4 .@.. .#.. #X#. .#..
 

Sample Output
  
  
1 2 -1


题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1733


题目意思:X代表人,@代表门,问什么时候可以让所有的人走出教室。

分层网络,枚举时间

每一次求出最大流都累加起来,直到等于X的数量,即 直到所有的X都走到@上。

建图时,因为不知道最后会有多少点,设置0为源点,1为汇点,初始化 源点到X(需要自己设置编号)的流量为1。每次增广时都会新增n*m个点,通过前一层的节点五个方向走到的当前层的节点,流量设为1。遍历地图,让当前层的点到汇点的流量设为1,,然后进行isap,将结果累加。

【数组下标开的小会造成时间超限】【事先进行dfs判断人是否能走出去】



#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define eps 1e-15
#define MAX(a,b) (a > b ? a : b)
#define MIN(a,b) (a < b ? a : b)
#define mem(a) memset(a,0,sizeof(a))


int n,m;
int s=1,t=2;
const int MAXN = 10000;//点数的最大值
const int MAXM = 2000000;//边数的最大值
const int INF = 0x3f3f3f3f;

int sumNum;//总点数
int sum;//人质的总数
int temp=0;//逃离的数目
char mp[20][20];
int vis[20][20];
int dir[5][2]= {0,1,0,-1,-1,0,1,0,0,0};

int dir2[4][2] =  {0,1,0,-1,-1,0,1,0};
int judge(int x,int y) {
    if (x>=0&&x<n&&y>=0&&y<m) {
        return 1;
    }
    return 0;
}
struct Edge {
    int to,next,cap,flow;
} edge[MAXM]; //注意是MAXM
int tol;
int head[MAXN];
int gap[MAXN],dep[MAXN],pre[MAXN],cur[MAXN];
void init() {
    tol = 0;
    sumNum=0;
    sum=0;
    temp=0;//计算最大流的点
    memset(head,-1,sizeof(head));
}
//加边,单向图三个参数,双向图四个参数
void addedge(int u,int v,int w,int rw=0) {
    edge[tol].to = v;
    edge[tol].cap = w;
    edge[tol].next = head[u];
    edge[tol].flow = 0;
    head[u] = tol++;
    edge[tol].to = u;
    edge[tol].cap = rw;
    edge[tol].next = head[v];
    edge[tol].flow = 0;
    head[v]=tol++;
}
//输入参数:起点、终点、点的总数
//点的编号没有影响,只要输入点的总数
int sap(int start,int end,int N) {
    memset(gap,0,sizeof(gap));
    memset(dep,0,sizeof(dep));
    memcpy(cur,head,sizeof(head));
    int u = start;
    pre[u] = -1;
    gap[0] = N;
    int ans = 0;
    while(dep[start] < N) {
        if(u == end) {
            int Min = INF;
            for(int i = pre[u]; i != -1; i = pre[edge[i^1].to])
                if(Min > edge[i].cap - edge[i].flow)
                    Min = edge[i].cap - edge[i].flow;
            for(int i = pre[u]; i != -1; i = pre[edge[i^1].to]) {
                edge[i].flow += Min;
                edge[i^1].flow -= Min;
            }
            u = start;
            ans += Min;
            continue;
        }
        bool flag = false;
        int v;
        for(int i = cur[u]; i != -1; i = edge[i].next) {
            v = edge[i].to;
            if(edge[i].cap - edge[i].flow && dep[v]+1 == dep[u]) {
                flag = true;
                cur[u] = pre[v] = i;
                break;
            }
        }
        if(flag) {
            u = v;
            continue;
        }
        int Min = N;
        for(int i = head[u]; i != -1; i = edge[i].next)
            if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min) {
                Min = dep[edge[i].to];
                cur[u] = i;
            }
        gap[dep[u]]--;
        if(!gap[dep[u]])return ans;
        dep[u] = Min+1;
        gap[dep[u]]++;
        if(u != start) u = edge[pre[u]^1].to;
    }
    return ans;
}
int dfs(int x,int y) {
    vis[x][y]=1;
    if (mp[x][y]=='@') {

        return 1;
    }
    for (int i=0; i<4; i++) {
        int xx=x+dir2[i][0];
        int yy=y+dir2[i][1];
        if (judge(xx,yy)&&vis[xx][yy]==0&&mp[xx][yy]!='#') {
            if (dfs(xx,yy)) {
                return 1;
            }
        }
    }
    return 0;
}
int f() {

    for (int i=0; i<n; i++) {
        for (int j=0; j<m; j++) {
            if (mp[i][j]=='X') {
                memset(vis,0,sizeof(vis));
                if (dfs(i,j)==0) {
                    return 0;
                }
            }
        }
    }
    return 1;
}
int  togo(int ti) {

    for (int i=0; i<n; i++) {
        for (int j=0; j<m; j++) {
            int u=i*m+j+2;
            u = u+ (ti-1)*m*n;
            if (mp[i][j]=='#') {
                continue;
            }
            for (int k=0; k<5; k++) {
                int xx = i+dir[k][0];
                int yy = j+dir[k][1];
                if (judge(xx,yy)) {
                    int v = xx*m+yy+2;
                    v = v+ti*m*n;
                    addedge(u,v,1);
                }
            }
        }
    }

    for (int i=0; i<n; i++) {
        for (int j=0; j<m; j++) {
            int u=i*m+j+2;
            u = u+ti*m*n;
            if (mp[i][j]=='@') {
                addedge(u,t,1);
            }
        }
    }
    sumNum+=n*m;
    temp += sap(s,t,sumNum);
    //  printf("%d\n",temp);
    return temp==sum;
}
int solve() {

    int ti=0;
    while (1) {
        ti++;
        if (togo(ti)) {
            break;
        }
    }
    return ti;
}
int main() {

    while (~scanf("%d %d",&n,&m)) {

        init();
        for(int i=0; i<n; i++) {
            scanf("%s",mp[i]);

        }
        if (!f()) {
            printf("-1\n");
            continue;
        }
        s=1,t=2;
        for (int i=0; i<n; i++) {
            for (int j=0; j<m; j++) {
                if (mp[i][j]=='X') {
                    int u = i*m+j+2;
                    addedge(s,u,1);
                    sum++;
                }
            }
        }
        if (sum==0){
            printf("0\n");
            continue;
        }
        sumNum+=n*m+2;
           printf("%d\n",solve());

    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值