题意:n个实验 每个实验可获利ai元 做每个实验需要几个仪器
购买每个仪器有不同的花费 不同实验可能会用到同一个仪器 只用购买一次 求最大收益
题解:............................................
先讲玄学建图吧
从s向每个实验连权值为仪器收益的边
从每个仪器向t连权值仪器花费的边
实验与仪器之间连INF的边
答案等于所有实验的收益 减去 (最大流=最小割)
感性的理解一下.. 你已经获得了实验的收益了 如果当前存在一条s->t的路径 那么就表示你这个实验 还欠缺着某个仪器没买
因为把仪器割掉的含义是买这个仪器 所以才会减去花费
如果把实验割掉了 那么显然就是不做这个实验
然后输出方案也学到一个trick 就是在最后一次bfs的时候 如果当前点跑不到 dis = INF 那么意味着到这个点的边权被减为0了 流满了 就是这个点被割掉了
在这个题里被割掉了就意味着 选择做实验 买仪器

#include <bits/stdc++.h> using namespace std; const int INF = 0x3f3f3f3f; int n, m, s, t, maxflow, cnt; struct node { int to, nex, val; }E[100005]; int head[105]; int cur[105]; void addedge(int x, int y, int va) { E[++cnt].to = y; E[cnt].nex = head[x]; head[x] = cnt; E[cnt].val = va; E[++cnt].to = x; E[cnt].nex = head[y]; head[y] = cnt; E[cnt].val = 0; } int dep[105]; int inque[105]; bool bfs() { for(int i = 1; i <= t; i++) dep[i] = INF, inque[i] = 0, cur[i] = head[i]; queue<int> que; que.push(s); dep[s] = 0, inque[s] = 1; while(!que.empty()) { int u = que.front(); que.pop(); inque[u] = 0; for(int i = head[u]; i; i = E[i].nex) { int v = E[i].to; if(E[i].val && dep[v] > dep[u] + 1) { dep[v] = dep[u] + 1; if(!inque[v]) { que.push(v); inque[v] = 1; } } } } return dep[t] != INF; } int vis; int dfs(int x, int flow) { if(x == t) { maxflow += flow; vis = 1; return flow; } int rflow = 0; int used = 0; for(int i = cur[x]; i; i = E[i].nex) { cur[x] = i; int v = E[i].to; if(E[i].val && dep[v] == dep[x] + 1) { if(rflow = dfs(v, min(flow - used, E[i].val))) { used += rflow; E[i].val -= rflow; E[i ^ 1].val += rflow; if(used == flow) break; } } } return used; } void dinic() { maxflow = 0; while(bfs()) { vis = 1; while(vis) { vis = 0; dfs(s, INF); } } } int p[55]; int c[55]; int ans[55]; int viss[55]; int ned[55][55]; char tools[10000]; int main() { int sum = 0; scanf("%d%d", &n, &m); s = n + m + 1; t = s + 1; cnt = 1; int ulen; for(int i = 1; i <= n; i++) { scanf("%d", &p[i]); sum += p[i]; addedge(s, i, p[i]); memset(tools, 0, sizeof(tools)); cin.getline(tools, 10000); ulen = 0; int num; while(sscanf(tools + ulen, "%d", &num) == 1) { ned[i][num] = 1; addedge(i, n + num, INF); if(num == 0) ulen++; else { while(num) { num /= 10; ulen++; } } ulen++; } } for(int i = 1; i <= m; i++) scanf("%d", &c[i]); for(int i = 1; i <= m; i++) addedge(n + i, t, c[i]); dinic(); for(int i = 1; i <= m; i++) { for(int j = head[i + n]; j; j = E[j].nex) { int v = E[j].to; if(v == t) { if(E[j].val == 0) viss[i] = 1; break; } } } for(int i = 1; i <= n; i++) { if(dep[i] != INF) printf("%d ", i); } puts(""); for(int i = 1; i <= m; i++) { if(dep[i + n] != INF) printf("%d ", i); } puts(""); printf("%d ", sum - maxflow); return 0; }