传送门
题意: 有n门课程, 每门都有一个智慧值和一个智力消耗值. 并且每门课程有0或多个先修课程, 即必须修了先修课程才能修该门课程. 问所有学过的课程的智慧值的和与智力消耗值的和的差值。请问,这个值最大是多少?
思路:有很明显的依赖关系, 如果u 是 v 的先修课程, 那么就连一条有向边v -> u, 然后每个点有自己的权值, 那就是自身的智慧值与智力消耗值的差值, 所以问题就很明显的是求最大权闭合子图. 直接建图, 套板子就即可…
结论: 最大权闭合子图的权值等于所有正权点之和减去最小割
AC Code
const int maxn = 5e2+5;
int cnt ;
int n, m, s, t;
bool vis[maxn];
int d[maxn], cur[maxn];
struct Edge {
int u, v;
int cap, flow;
} e[maxn*maxn]; //因为是双向边 所以记得开二倍
vector<int> G[maxn];
void init() {
for (int i = 0; i <= n + 1; i++)
G[i].clear();
cnt = 0;
}
void add(int u, int v, int cap, int f) {
e[cnt].u = u;
e[cnt].cap = cap;
e[cnt].flow = f;
e[cnt].v = v;
}
void AddEdge(int u, int v, int cap) {
add(u, v, cap, 0);
G[u].push_back(cnt++);
add(v, u, 0, 0);
G[v].push_back(cnt++);
}
bool BFS() {
Fill(vis, 0);
queue<int> q; q.push(s);
vis[s] = 1; d[s] = 0;
while (!q.empty()) {
int v = q.front(); q.pop();
for (int i = 0; i < G[v].size(); i++) {
Edge &te = e[G[v][i]];
if (!vis[te.v] && te.cap > te.flow) { //只考虑残量网络的弧
vis[te.v] = 1;
d[te.v] = d[v] + 1;
q.push(te.v);
}
}
}
return vis[t];
}
int dfs(int x, int a) {
if (x == t || a == 0) return a;
int flow = 0, f;
for (int &i = cur[x]; i < G[x].size(); i++) { //从上次考虑的弧
Edge &te = e[G[x][i]];
if (d[x] + 1 == d[te.v] && (f = dfs(te.v, min(a, te.cap - te.flow))) > 0) {
te.flow += f;
e[G[x][i]^1].flow -= f;
flow += f;
a -= f;
if (a == 0) break;
}
}
return flow;
}
int Dinic() {
int flow = 0;
while (BFS()) {
Fill(cur, 0);
flow += dfs(s, inf);
}
return flow;
}
void solve() {
scanf("%d", &n); init();
s = 0, t = n + 1; int ans = 0;
for (int i = 1 ; i <= n ; i ++) {
int a, b;
scanf("%d%d", &a, &b);
a -= b;
if (a > 0) AddEdge(s, i, a), ans += a;
if (a < 0) AddEdge(i, t, -a);
}
int u, v;
while(~scanf("%d%d", &u, &v)) {
AddEdge(v, u, inf);
}
printf("%d\n", ans - Dinic());
}