uva563 (最大流 & 拆点)

题目大意:
有一个n × m的网点状街区,在这个n × m的街区上,有l家银行。有一伙劫匪要去抢银行,抢完以后要跑,他们逃跑的路线不能重叠,逃出n × m的街区边界才算是逃跑成功。给出街区大小和各银行位置,问是否可以全部成功逃脱。

思路:
构造一个超级源点,与被抢劫的银行相连接,然后边界与超级汇点相连接,每个十字路口的点都要进行拆点,它们之间的容量为1,因为每个十字路口只能有一个人走,十字路口的点还要和它四面八方的点进行连接,它四面八方的点可能是边界,这样就可以构成一个图。
最后判断最大流是否等于被抢银行的数量,如果是的话,就可以,如果不是的话,就不可以。
注意:要进行拆点。
代码:

#include <iostream>
using namespace std;
#include <cstring>
#include <stdio.h>
#include <cstring>
#include <queue>

const int MAX = 30010;
const int MAXN = 5010;
const int INF =0x3f3f3f3f;
struct node {
    int u,v,ne,flow,cap;
}e[MAX];
int dir[4][2] = {1,0,-1,0,0,1,0,-1};
int pre[MAXN];
int p[MAXN];
int mr[MAXN];
int edgenum;
int n,m,num,s,t,F;

void add(int u,int v) {
    e[edgenum].u = u;
    e[edgenum].v = v;
    e[edgenum].flow = 0;
    e[edgenum].cap = 1;
    e[edgenum].ne = pre[u];
    pre[u] = edgenum++;
    e[edgenum].v = u;
    e[edgenum].u = v;
    e[edgenum].flow = 0;
    e[edgenum].cap = 0;
    e[edgenum].ne = pre[v];
    pre[v] = edgenum++;
}
void init() {
    memset(pre,-1,sizeof(pre));
    edgenum = 0;
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            int u = (i - 1) * m + j;
            int e = u + n * m;
            add(u,e);
            for(int k = 0; k < 4; k++) {
                int x = i + dir[k][0];
                int y = j + dir[k][1];
                if(x >= 1 && x <= n && y >= 1 && y <= m) {
                    int uu = (x - 1) * m + y;
                    add(e,uu);
                }
                else
                    add(e,t);
            }
        }
    }
    int u,v;
    for(int i = 1; i <= num; i++) {
        scanf("%d %d",&u,&v);
        add(s,(u - 1) * m + v);
    }
}
void EK() {
    queue<int> q;
    F = 0;
//  memset(p,0,);
    while(1) {
        memset(p,-1,sizeof(0));
        memset(mr,0,sizeof(mr));
        mr[0] = INF;
        q.push(0);
        while(!q.empty()) {
            int u = q.front();
            q.pop();
            for(int k = pre[u]; k != -1; k = e[k].ne) {
                int v = e[k].v;
                if(!mr[v] && e[k].cap > e[k].flow) {
                    p[v] = k;
                    q.push(v);
                    mr[v] = min(mr[u],e[k].cap - e[k].flow);
                }
            }
        }
        if(mr[t] == 0) break;
        for(int k = p[t];k != -1; k = p[e[k^1].v]) {
            e[k].flow += mr[t];
            e[k^1].flow -= mr[t];
        }
        F += mr[t];
    }
}
int main() {
    int T;
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d%d",&n,&m,&num);
        s = 0;
        t = n * m * 2 + 1;
        init();
        EK();
        if(F == num)
            printf("possible\n");
        else
            printf("not possible\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值