这道题不是好久之前做的了
填一下网络流24题的坑
本质上是个最大权闭合图问题的模板 (话说这么多问题,我怎么记得住)
在源点\(S\)和每个实验之间连一条边权为实验利益的边
在每个实验和它需要的仪器之间连一条边权为\(+\infty\)的边
在仪器和汇点\(t\)之间连一条边权为仪器花费的边
然后跑最小割就好了
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #define LL long long #define inf 0x7fffffff using namespace std; LL read() { LL k = 0, f = 1; char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') k = k * 10 + c - 48, c = getchar(); return k * f; } struct zzz { int t, nex, len; }e[100010 << 1]; int head[1010], tot = 1; void add(int x, int y, int z) { e[++tot].t = y; e[tot].len = z; e[tot].nex = head[x]; head[x] = tot; } int s, t; int vis[110]; bool bfs() { memset(vis, 0, sizeof(vis)); queue <int> q; q.push(s); vis[s] = 1; while(!q.empty()) { int k = q.front(); q.pop(); for(int i = head[k]; i; i = e[i].nex) { if(!vis[e[i].t] && e[i].len) { vis[e[i].t] = vis[k] + 1; if(e[i].t == t) return 1; q.push(e[i].t); } } } return vis[t]; } int dfs(int x, int flow) { if(!flow || x == t) return flow; int rest = 0, fl; for(int i = head[x]; i; i = e[i].nex) { if(vis[e[i].t] == vis[x] + 1 && (fl = dfs(e[i].t, min(flow - rest, e[i].len)))) { rest += fl; e[i].len -= fl; e[i^1].len += fl; if(rest == flow) return rest; } } if(rest < flow) vis[x] = 0; return rest; } int dinic() { int ans = 0; while(bfs()) ans += dfs(s, inf); return ans; } int main() { //freopen("1.txt", "w", stdout); int m = read(), n = read(); s = m+n+1, t = m+n+2; int sum = 0; for(int i = 1; i <= m; ++i) { int x = read(); sum += x; add(s, i, x), add(i, s, 0); char tools[10000]; memset(tools, 0, sizeof tools); cin.getline(tools, 10000); int ulen=0,tool; while(sscanf(tools+ulen, "%d", &tool) == 1) { add(i, tool+m, inf); add(tool+m, i, 0); if(tool == 0) ulen++; else while(tool) tool /= 10, ulen++; ulen++; } } for(int i = 1; i <= n; ++i) { int x = read(); add(i+m, t, x); add(t, i+m, 0); } sum -= dinic(); for(int i = 1; i <= m; ++i) if(vis[i]) cout << i << ' '; cout << endl; for(int i = 1; i <= n; ++i) if(vis[i+m]) cout << i << ' '; cout << endl; cout << sum; return 0; }