题意:
每条路只能走一个人,不能在有交叉的点,要保证所有的银行都覆盖住
思路:
如果汇点的容量如果是银行总数那么自然所有的银行都走过了,这要求每个银行都拉成一条容量为1的线,起点通向0,终点通向maxn(自己设定,在边界外),且表格内每个点都通向终点,容量为1,这保证了容量最多是银行数量,且逃跑后每条路只有一个人
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int maxx = 5005;
const int maxn = 5001;//创造终点
const int flag = 2500;//拆点
const int INF = 0x3f3f3f3f;
struct edge {
int s, t, f, c;
edge(int q, int w, int e, int r) {
s = q;
t = w;
f = e;
c = r;
}
edge() {}
};
int dir[4][2] = {{-1,0}, {1,0}, {0,-1}, {0,1}};
vector<edge>v;
vector<int> g[maxx];//给个起点的终点在v中下标
int n, m, l;
void add(int from, int to) {
v.push_back((edge){from, to, 0, 1});
v.push_back((edge){to, from, 0, 0});
int len = v.size();
g[from].push_back(len-2);
g[to].push_back(len-1);
}
void init() {
for(int i=0; i<=n*n; i++) g[i].clear();
v.clear();
}
void input2() {
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++) {
if(i==1 || i==n || j==1 || j==m)//边界通向终点
add((i-1)*m+flag+j, maxn);
add((i-1)*m+j, (i-1)*m+flag+j);
for(int k=0; k<4; k++) {
int x = i+dir[k][0];
int y = j+dir[k][1];
if(x<1 || x>n) continue;
if(y<1 || y>m) continue;
add((i-1)*m+j+flag, (x-1)*m+y);
}
}
int x, y;
for(int i=0; i<l; i++) {
scanf("%d%d", &x, &y);
add(0, (x-1)*m+y);
}
}
int ek2() {
int p[maxx];
int a[maxx];
int ans = 0;
memset(p, 0, sizeof(p));
queue<int>q;
while(1) {
memset(a, 0, sizeof(a));
a[0] = INF;
q.push(0);
while(!q.empty()) {
int u = q.front();
q.pop();
for(int i=0; i<g[u].size(); i++) {
edge& w = v[g[u][i]];
if(!a[w.t] && w.c>w.f) {
//printf("%d %d\n", u, w.s);
a[w.t] = min(a[u], w.c-w.f);
p[w.t] = g[u][i];
q.push(w.t);
}
}
}
if(a[maxn]==0) break;
ans += a[maxn];
for(int i=maxn; i; i=v[p[i]].s) {
v[p[i]].f += a[maxn];
v[p[i]^1].f -= a[maxn];
}
}
return ans;
}
int main() {
int kase;
scanf("%d", &kase);
while(kase--) {
scanf("%d%d%d", &n, &m, &l);
init();
input2();
int ans = ek2();
if(ans == l) printf("possible\n");
else printf("not possible\n");
}
return 0;
}
有一个很奇怪的地方:
a[w.t] = min(a[w.s], w.c-w.f) 是超时的
我试着打出来 w.s与u,他们是一样的,不知道为什么就朝超时了