UVa 563 - Crimewave 最大流

Nieuw Knollendam is a very modern town. This becomes clear already when looking at the layoutof its map, which is just a rectangular grid of streets and avenues. Being an important trade centre,Nieuw Knollendam also has a lot of banks. Almost on every crossing a bank is found (although thereare never two banks at the same crossing). Unfortunately this has attracted a lot of criminals. Bankhold-ups are quite common, and often on one day several banks are robbed. This has grown into aproblem, not only to the banks, but to the criminals as well. After robbing a bank the robber tries toleave the town as soon as possible, most of the times chased at high speed by the police. Sometimestwo running criminals pass the same crossing, causing several risks: collisions, crowds of police at oneplace and a larger risk to be caught.

To prevent these unpleasant situations the robbers agreed to consult together. Every Saturday nightthey meet and make a schedule for the week to come: who is going to rob which bank on which day?For every day they try to plan the get-away routes, such that no two routes use the same crossing.Sometimes they do not succeed in planning the routes according to this condition, although they believethat such a planning should exist.

Given a grid of (s×a) and the crossings where the banks to be robbed are located, find out whetheror not it is possible to plan a get-away route from every robbed bank to the city-bounds, without usinga crossing more than once.

Input

The first line of the input contains the number of problems p to be solved.

• The first line of every problem contains the number s of streets (1 ≤ s ≤ 50), followed by thenumber a of avenues (1 ≤ a ≤ 50), followed by the number b (b ≥ 1) of banks to be robbed.

• Then b lines follow, each containing the location of a bank in the form of two numbers x (thenumber of the street) and y (the number of the avenue). Evidently 1 ≤ x ≤ s and 1 ≤ y ≤ a.

Output

The output file consists of p lines. Each line contains the text ‘possible’ or ‘not possible’. If it ispossible to plan non-crossing get-away routes, this line should contain the word: ‘possible’. If this isnot possible, the line should contain the words ‘not possible’.

Note: The picture on the right illustrates the first sample inputbelow. 

Sample Input

6 6 10

4 1

3 2

4 2

5 2

3 4

4 4

5 4

3 6

4 6

5 6

5 5 5                                                                                                           

3 2

2 3

3 3

4 3

3 4

Sample Output

possible

not possible

题意:给你s * a 的矩阵,每个点只能经过一次,再给你b个人,问能否让这b个人成功走出矩阵。

思路:

建立超级源点s,t,将每个盗贼的位置与超级源点s相连,flow是1.由于每个点最多只能走一次,所以要进行拆点,将点u->u',flow为1,因为逃到四面八方任意一个边界就可以了,所以将边界点与超级汇点t进行连接,flow为1,中间的路径,不是边界上的点i要跟前后左右进行建边。然后运用isap跑一遍最大流,flow==b则有解,否则无解。建模过程是重点。

#include <stdio.h>  
#include <string.h>  
#include <algorithm>  
#define REP(I, X) for(int I = 0; I < X; ++I)  
#define FF(I, A, B) for(int I = A; I <= B; ++I)  
#define clear(A, B) memset(A, B, sizeof A)  
#define copy(A, B) memcpy(A, B, sizeof A)  
#define min(A, B) ((A) < (B) ? (A) : (B))  
#define max(A, B) ((A) > (B) ? (A) : (B))  
using namespace std;  
typedef long long ll;  
typedef long long LL;  
const int oo = 0x3f3f3f3f;  
const int maxE = 200000;  
const int maxN = 5005;  
const int maxQ = 10000;  
struct Edge{  
    int v, c, n;  
};  
Edge edge[maxE];  
int adj[maxN], cntE;  
int Q[maxE], head, tail, inq[maxN];  
int d[maxN], num[maxN], cur[maxN], pre[maxN];  
int s, t, nv;  
int n, m, nm;  
int path[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};  
void addedge(int u, int v, int c){  
    edge[cntE].v = v; edge[cntE].c = c; edge[cntE].n = adj[u]; adj[u] = cntE++;  
    edge[cntE].v = u; edge[cntE].c = 0; edge[cntE].n = adj[v]; adj[v] = cntE++;  
}  
void REV_BFS(){  
    clear(d, -1);  
    clear(num, 0);  
    head = tail = 0;  
    d[t] = 0;  
    num[0] = 1;  
    Q[tail++] = t;  
    while(head != tail){  
        int u = Q[head++];  
        for(int i = adj[u]; ~i; i = edge[i].n){  
            int v = edge[i].v;  
            if(~d[v]) continue;  
            d[v] = d[u] + 1;  
            num[d[v]]++;  
            Q[tail++] = v;  
        }  
    }  
}  
int ISAP(){  
    copy(cur, adj);  
    REV_BFS();  
    int flow = 0, u = pre[s] = s, i;  
    while(d[s] < nv){  
        if(u == t){  
            int f = oo, neck;  
            for(i = s; i != t; i = edge[cur[i]].v){  
                if(f > edge[cur[i]].c){  
                    f = edge[cur[i]].c;  
                    neck = i;  
                }  
            }  
            for(i = s; i != t; i = edge[cur[i]].v){  
                edge[cur[i]].c -= f;  
                edge[cur[i] ^ 1].c += f;  
            }  
            flow += f;  
            u = neck;  
        }  
        for(i = cur[u]; ~i; i = edge[i].n) if(edge[i].c && d[u] == d[edge[i].v] + 1) break;  
        if(~i){  
            cur[u] = i;  
            pre[edge[i].v] = u;  
            u = edge[i].v;  
        }  
        else{  
            if(0 == (--num[d[u]])) break;  
            int mind = nv;  
            for(i = adj[u]; ~i; i = edge[i].n){  
                if(edge[i].c && mind > d[edge[i].v]){  
                    mind = d[edge[i].v];  
                    cur[u] = i;  
                }  
            }  
            d[u] = mind + 1;  
            num[d[u]]++;  
            u = pre[u];  
        }  
    }  
    return flow;  
}  
void work(){  
    int x, y, b;  
    clear(adj, -1);  
    cntE = 0;  
    scanf("%d%d%d", &n, &m, &b);  
    nm = n * m;
      
    s = nm * 2;//之前0-nm*2-1是图中的坐标的点们,所以规定nm*2是s点,nm*2+1是点t
    t = s + 1; 
    nv = t + 1; //因为是d[s] < nv ,所以要加一
    REP(x, n) REP(y, m){  
        int xy = x * m + y;  
        addedge(xy, xy + nm, 1);//拆点操作!!!必不可少!!!为了保证每个点只走一次 
        if(x == 0 || y == 0 || x == n - 1|| y == m - 1)//在一圈的边界上,建立与t的边,flow为1
            addedge(nm + xy, t, 1);  
        else REP(k, 4)
        {  
            int nx = x + path[k][0];  
            int ny = y + path[k][1];  
            addedge(xy + nm, nx * m + ny, 1);//上下左右进行建边  
        }  
    }  
    REP(i, b)
    {  
        scanf("%d%d", &x, &y);  
        --x; --y;//因为是从0开始的  
        addedge(s, x * m + y, 1);//将盗贼的位置和源点进行建边,flow为1
    }  
    printf(b == ISAP() ? "possible\n" : "not possible\n");  
}  
int main(){  
    int T;  
    for(scanf("%d", &T); T; --T) work();  
    return 0;  
}  
文章参考:
http://blog.csdn.net/u013368721/article/details/27802709

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值