UVa 563 Crimewave ( 用最大流判断,拆点)

这道题主要思想就是建图,拆点,判断

判断最大流是不是等于银行个数

拆点,每个点只能经过一次,有容量的点都拆成进点和出点,从进点进,从出点出

建图,将所有的点重新编号,bank和的进点和源点相连,容量为1;grid的四框上的点的拆出来的点和汇点相连,容量INF;每个点对应的进入点和出点容量为1;每个点的出点和上下左右的点的进点相连,容量为1

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

const int M = 50000;
const int N = 10000;
const int INF = 1000000;
int P, n, m, bank, idx, pnum, S, T, head[N];
struct edge{
    int v, next;
    int cap, flow;
}e[M];
void add( int u, int v, int c ) {
    e[idx].next = head[u];
    e[idx].v = v;
    e[idx].cap = c;
    e[idx].flow = 0;
    head[u] = idx++;

    e[idx].next = head[v];
    e[idx].flow = e[idx].cap = 0;
    e[idx].v = u;
    head[v] = idx++;
}
void init () {
        idx = 0;
        pnum = n*m*2+1;
        int ori = n*m;
        S = 0; T = pnum;
        for ( int i = 0; i <= pnum; ++i ) head[i] = -1;
        for ( int i = 0; i < n; ++i )
           for ( int j = 1; j <= m; ++j ) {
               int p1 = i*m+j, p2 = i*m+j+ori;
               add( p1, p2, 1 );
               if ( j + 1 <= m ) add( p2, p1 + 1, INF );  //right
               else add( p2, T, INF );
               if ( i + 1 < n )add( p2, p1 + m, INF );  // down
               else add( p2, T, INF );
               if ( i > 0 ) add( p2, p1 - m, INF );  // up
               else add( p2, T, INF );
               if ( j > 1 ) add( p2, p1 -1, INF );  // left
               else add( p2, T, INF );
           }
        for ( int i = 0; i < bank; ++i ) {
            int x, y;
            scanf("%d%d", &x, &y);
            int p = (x-1)*m + y;
            add( S, p, 1 );
        }
}
int maxflow() {
    int f = 0;
    queue<int> q;
    int r[N], a[N], p[N];
    while ( 1 ) {
        memset(a, 0, sizeof(a));
        a[S] = INF;
        q.push(S);
        while ( !q.empty() ) {
            int u = q.front(); q.pop();
            for ( int i = head[u]; i != -1; i = e[i].next ) {
                int cap = e[i].cap, flow = e[i].flow, v = e[i].v; 
                if ( !a[v] && cap > flow ) {
                    p[v] = u, r[v] = i; q.push(v);
                    a[v] = min( a[u], cap - flow );
                }
            }
        }
        if ( a[T] == 0 ) break;
        for ( int u = T; u != S; u = p[u] ) {
            int ri = r[u];
            e[ri].flow += a[T];
            e[ri^1].flow -= a[T];
        }
        f += a[T];
    }
    //printf("%d\n", f);
    return f;
}
int main()
{
    scanf("%d", &P);
    while ( P-- ) {
        scanf("%d%d%d", &n, &m, &bank);
        init();
        if ( bank == maxflow() ) printf("possible\n");
        else printf("not possible\n");
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值