题目大意:在一个r*c的城市中,有n个银行,有一个抢匪想抢劫这n家银行,每次抢劫后需逃离城市(移动到坐标外),但是又不能走先前走过的位置,给出n个银行的坐标,问说抢匪能非成功抢劫银行并且逃脱。
解题思路:很经典的逃脱问题,要不是因为在刷网络流的专题根本想不到要用网络流去做。
首先先讲每个点与它周围的4个点建立一条边,表示可以移动。(注意要拆点,因为每个点都有容量限制,即只能走过一次,所以对于点c,要建立一个c‘,c’指向c有一条容量大小为1的边,所有与c点有关的点所建立的边统统指向c‘,而c点指向其他点的边任然保留在c上)
其次是建立汇点t,将所有的边界点指向汇点。
然后读入n个银行的坐标,对应的建立起点s与银行间的边。
最后是最大流问题,计算出从起点s到汇点t的最大流值ans,若ans等于n,说明成功,否则失败。
昨天晚上做一一晚上这道题目,一直RE,最后到会宿舍才发现说在拆点的时候,c ->c’ = c + T; T = R * C才对,应该是2500,但我一直以为是250,郁闷啊~
还有这道题应该用邻接表的来储存关系,不过因为做得太纠结,就懒得改了,数组开太大,时间有点久。
#include <stdio.h>
#include <string.h>
#include <queue>
#define min(a,b) (a)<(b)?(a):(b)
#define max(a,b) (a)>(b)?(a):(b)
using namespace std;
const int N = 5010;
const int T = 2500;
const int INF = 1 << 20;
const int dir[10][2] = { {0, 1}, {1, 0}, {0, -1}, {-1, 0} };
int r, c, n, tmp;
int p[N][N], f[N][N];
int g[N][T + 10], son[N];
void add(int x, int y) {
p[x][y] = 1;
g[x][son[x]++] = y;
}
void init() {
memset(g, 0, sizeof(g));
memset(son, 0, sizeof(son));
memset(p, 0, sizeof(p));
memset(f, 0, sizeof(f));
scanf("%d%d%d", &r, &c, &n);
tmp = 5001;
for (int i = 1; i <= r; i++) {
for (int j = 1; j <= c; j++) {
if (i == 1 || j == 1 || i == r || j == c)
add( (i-1) * c + j, 0);
add( (i-1) * c + j + T, (i-1) * c + j);
for (int k = 0; k < 4; k++) {
int p = i + dir[k][0], q = j + dir[k][1];
if (p <= 0 || p > r) continue;
if (q <= 0 || q > c) continue;
add( (i-1) * c + j, (p-1) * c + q + T);
}
}
}
int a, b;
for (int i = 0; i < n; i++) {
scanf("%d%d\n", &a, &b);
add(tmp, (a-1) * c + b + T);
}
}
int solve() {
int ans = 0;
int k, s[N], path[N];
queue<int> que;
while (1) {
memset(path, 0, sizeof(path));
memset(s, 0, sizeof(s));
path[tmp] = tmp;
s[tmp] = INF;
que.push(tmp);
while (!que.empty() ) {
k = que.front(), que.pop();
for (int i = 0; i < son[k]; i++) {
if ( !s[g[k][i]] && p[k][g[k][i]] > f[k][g[k][i]]) {
s[g[k][i]] = min(s[k], p[k][g[k][i]] - f[k][g[k][i]]);
path[g[k][i]] = k;
que.push(g[k][i]);
}
}
}
if (s[0] == 0) break;
ans += s[0];
for (int i = 0; i != tmp; i = path[i]) {
f[path[i]][i] += s[0];
f[i][path[i]] -= s[0];
}
}
return ans;
}
int main () {
int cas;
scanf("%d", &cas);
while (cas--) {
init();
int ans = solve();
printf("%s\n", ans == n ? "possible" : "not possible");
}
return 0;
}