这道题主要思想就是建图,拆点,判断
判断最大流是不是等于银行个数
拆点,每个点只能经过一次,有容量的点都拆成进点和出点,从进点进,从出点出
建图,将所有的点重新编号,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");
}
}