题意:一张有向图由n个点构成,每个点都有一个容量限制,然后给出多个源点和多个汇点。
经典的模型,拆点,构造超级源点和超级汇点,然后用最大流算法即可。
注意要小心构造图。
代码:
/*
* Author: illuz <iilluzen[at]gmail.com>
* Blog: http://blog.csdn.net/hcbbt
* File: uva10330.cpp
* Create Date: 2013-12-06 15:51:52
* Descripton: 拆点, max flow
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
const int MAXN = 210;
const int INF = 0X3C3C3C3C;
int mr[MAXN]; // 从源点到i的最小残量
int p[MAXN]; // 更新时i的上流节点
int c[MAXN][MAXN], f[MAXN][MAXN]; // capitar and flow
int maxFlow(int op, int ed, int n) // start, end, num of points
{
queue<int> q;
memset(f, 0, sizeof(f));
memset(p, 0, sizeof(p));
int F = 0; // total flow
// bfs
while (1) {
memset(mr, 0, sizeof(mr));
q.push(op);
mr[op] = INF; // 源点残量
while (!q.empty()) {
int u = q.front();
q.pop();
for (int v = 0; v < n; v++)
if (!mr[v] && c[u][v] > f[u][v]) {
p[v] = u;
q.push(v);
mr[v] = min(mr[u], c[u][v] - f[u][v]);
}
}
if (mr[ed] == 0) return F;
// update
for (int u = ed; u != op; u = p[u]) {
f[u][p[u]] -= mr[ed];
f[p[u]][u] += mr[ed];
}
F += mr[ed];
}
}
int main() {
int n, nn, en, b, d, u, v, cast;
while (scanf("%d", &n) != EOF) {
memset(c, 0, sizeof(c));
// 拆点
for (int i = 1; i <= n; i++)
scanf("%d", &c[i][i + n]);
scanf("%d", &en);
while (en--) {
scanf("%d%d%d", &u, &v, &cast);
c[u + n][v] = cast; // 这里也要处理
}
// 构建超级源点和超级汇点
scanf("%d%d", &b, &d);
while (b--) {
scanf("%d", &u);
c[0][u] = INF;
}
while (d--) {
scanf("%d", &u);
c[u + n][2 * n + 1] = INF;
}
printf("%d\n", maxFlow(0, 2 * n + 1, 2 * n + 2));
}
return 0;
}