题意
有 \(m\) 组实验, \(n\) 个器材,
每个实验需要若干个器材, 可以获得一定收益, 每个器材有一定的费用,
求最大净收益 (总收益 - 总费用), 并输出方案.
思路
将每个器材连向 \(S\), 边权为器材的费用,
将每个实验连向 \(T\), 边权为实验的收益,
每个器材向需要它的实验连边, 边权为 \(inf\),
跑最小割就行了.
需要注意的是, 最后输出方案, 判断每个器材是否被选中时, 不能单纯地判断 \(S\) 连向它的边权是否为 \(0\),
因为就算边权为 \(0\), \(S\) 还是能够通过其他路径增广它,
所以应该判断 \(Dinic\) 算法最后一次 \(bfs\) 时有没有经过它, 如果没有经过, 就表示它被选中了.
代码
#include<bits/stdc++.h> #define pb push_back #define sz size using namespace std; const int _=100+7; const int __=20400+7; const int inf=0x3f3f3f3f; int n,m,S,T,d[_],max_flow,ans; int lst[_],nxt[__],to[__],c[__],tot=1; char tools[10000]; queue<int> q; vector<int> nd[_]; void add(int x,int y,int w){ nxt[++tot]=lst[x]; to[tot]=y; c[tot]=w; lst[x]=tot; } void read(){ cin>>m>>n; m+=n; S=m+1; T=m+2; int x; for(int i=n+1;i<=m;i++){ scanf("%d",&x); ans+=x; add(i,T,x); add(T,i,0); memset(tools,0,sizeof tools); cin.getline(tools,10000); int ulen=0,tool; while (sscanf(tools+ulen,"%d",&tool)==1) { if (tool==0) ulen++; else { add(tool,i,inf); add(i,tool,0); nd[i-n].pb(tool); while (tool) { tool/=10; ulen++; } } ulen++; } } for(int i=1;i<=n;i++){ scanf("%d",&x); add(S,i,x); add(i,S,0); } } bool bfs(){ for(int i=1;i<=T;i++) d[i]=0; while(!q.empty()) q.pop(); q.push(S); d[S]=1; while(!q.empty()){ int u=q.front(); q.pop(); for(int i=lst[u];i;i=nxt[i]){ int v=to[i]; if(d[v]||!c[i]) continue; d[v]=d[u]+1; if(v==T) return 1; q.push(v); } } return 0; } int dfs(int u,int flow){ if(u==T) return flow; int rest=flow; for(int i=lst[u];i;i=nxt[i]){ int v=to[i]; if(d[v]!=d[u]+1||!c[i]) continue; int cost=dfs(v,min(rest,c[i])); c[i]-=cost; c[i^1]+=cost; rest-=cost; } return flow-rest; } void Dinic(){ int flow; while(bfs()) do{ flow=dfs(S,inf); max_flow+=flow; }while(flow); ans-=max_flow; } void print(){ for(int u=1;u<=m-n;u++){ bool flag=1; for(int i=0;i<(int)nd[u].sz();i++) if(d[nd[u][i]]){ flag=0; break; } if(flag) printf("%d ",u); } putchar('\n'); for(int i=1;i<=n;i++) if(!d[i]) printf("%d ",i); putchar('\n'); printf("%d\n",ans); } int main(){ //freopen("x.in","r",stdin); read(); Dinic(); print(); return 0; }
来源:https://www.cnblogs.com/brucew-07/p/12185535.html