题目大意:一张无向图$G=(V,E)$,定义$f(G)=sumlimits_{ein E}w_e-sumlimits_{vin V}w_v$,给一张$n(nleqslant10^3)$个点$m(mleqslant10^3)$条边的无向图,求$max_{G'in G}{f(G')}$。
题解:最大权闭合子图。
有代价物品往选了它可能产生收益的组连边权为的边。
每个组往汇点连边权为其收益的边。
由源点向原图中的每条边连一条容量为其收益的边,原图中的边向它的两个端点连容量为$infty$的边,原图中的每个点向汇点连容量为其代价的边
把总收益减去最小割即可
卡点:无
C++ Code:
#include <algorithm> #include <cstdio> #define maxn 1010 #define maxm 1010 const int N = maxn + maxm, M = N + 2 * maxm; const int inf = 0x3f3f3f3f; namespace Network_Flow { int lst[N], head[N], cnt = 1; struct Edge { int to, nxt, w; } e[M << 1]; inline void addedge(int a, int b, int c) { e[++cnt] = (Edge) { b, head[a], c }; head[a] = cnt; e[++cnt] = (Edge) { a, head[b], 0 }; head[b] = cnt; } long long MF; int n, st, ed; int GAP[N], d[N]; int q[N], h, t; void init() { GAP[d[ed] = 1] = 1; for (int i = 0; i < n; ++i) lst[i] = head[i]; q[h = t = 0] = ed; while (h <= t) { int u = q[h++]; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (!d[v]) { d[v] = d[u] + 1; ++GAP[d[v]]; q[++t] = v; } } } } int dfs(int u, int low) { if (!low || u == ed) return low; int w, res = 0; for (int &i = lst[u]; i; i = e[i].nxt) if (e[i].w) { int v = e[i].to; if (d[u] == d[v] + 1) { w = dfs(v, std::min(low, e[i].w)); res += w, low -= w; e[i].w -= w, e[i ^ 1].w += w; if (!low) return res; } } if (!(--GAP[d[u]])) d[st] = n + 1; ++GAP[++d[u]], lst[u] = head[u]; return res; } void ISAP(int S, int T) { st = S, ed = T; init(); while (d[st] <= n) MF += dfs(st, inf); } } using Network_Flow::addedge; int n, m; long long sum; int main() { scanf("%d%d", &n, &m); Network_Flow::n = n + m + 2; int st = 0, ed = n + m + 1; for (int i = 1, x; i <= n; ++i) { scanf("%d", &x); addedge(st, i, x); } for (int i = 1, a, b, c; i <= m; ++i) { scanf("%d%d%d", &a, &b, &c); addedge(a, n + i, inf); addedge(b, n + i, inf); addedge(n + i, ed, c); sum += c; } Network_Flow::ISAP(st, ed); printf("%lld ", sum - Network_Flow::MF); return 0; }