题意如下,有多个小偷 从 s 点逃往 h 点,有 N 个城市, m 条路,每个城市最少需要 x 个 警察驻守才能防守住,问最少需要多少个警察才能把全部小偷堵住。。。
最小割。。。一眼就能看出来。转化最大流,因为每个城市要 X 个警察才能守住,我们就对其进行拆点,有了上一题经验,既然求最小割,我们把题目里的边容量设成 INF 来防止被割,然后跑一边最大流就可以成功的 割点了。。
换了个板子。。。感觉神清气爽。。。。
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1e5+5;
const int INF = 0x3f3f3f3f;
int head[maxn],cnt;
int h[maxn];
struct node
{
int to;
int cap;
int next;
}edge[2 * maxn];
void init()
{
memset(head, -1, sizeof(head));
cnt = 0;
}
void add(int u, int v, int cap)
{
edge[cnt].to = v, edge[cnt].cap = cap, edge[cnt].next = head[u], head[u] = cnt++;
edge[cnt].to = u, edge[cnt].cap = 0 , edge[cnt].next = head[v], head[v] = cnt++;
}
bool bfs(int s, int t)
{
memset(h, 0, sizeof(h));
queue<int>q;
h[s] = 1;
q.push(s);
while (q.size())
{
int u = q.front();
q.pop();
for (int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if (edge[i].cap > 0 && h[v] < 0)
{
h[v] = h[u] + 1;
q.push(v);
}
}
}
return h[t];
}
int dfs(int u, int t, int num)
{
if (u == t)
return num;
for (int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if (edge[i].cap > 0 && h[u] + 1 == h[v])
{
int d = dfs(v, t, min(num, edge[i].cap));
if (d > 0)
{
edge[i].cap -= d;
edge[i ^ 1].cap += d;
return d;
}
}
}
h[u] = -1;
return 0;
}
int dinic(int s, int t)
{
int sum = 0, num;
while (bfs(s, t))
{
while(num = dfs(s, t, INF) && num > 0)
{
sum += num;
}
}
return sum;
}
int T, a, b;
int n, m, s, t;
int main()
{
cin >> T;
while (T--)
{
init();
cin >> n >> m >> s >> t;
add(s, s + n, INF);
add(t, t + n, INF);
for (int i = 1; i <= n; i++)
{
cin >> a;
add(i, i + n, a);// 拆点
}
for (int i = 1; i <= m; i++)
{
cin >> a >> b;
add(a + n, b, INF);
add(b + n, a, INF);
}
cout << dinic(s, t + n) << endl;
}
return 0;
}