[网络流24题] 太空飞行计划问题 (最大流->最大权闭合图)
做这道题之前建议先看这篇论文,虽然论文里很多地方用了很多术语,但hbt神犇讲得很明白
这篇题解更加偏向于感性理解
把问题放到二分图上,左侧一列点是实验,权值为$p[i]$,右侧一列点是仪器,权值为$c[i]$,左侧向右侧连接了许多条出边
如果想获得$p[i]$,需要保证i的所有出边都被选上了
按照论文里最大权闭合图的做法,实验和源点$s$相连,流量为$p[i]$,仪器和汇点$t$相连,流量为$c[i]$,实验和仪器之间的边流量为$inf$
最终的答案就是实验带来的报酬总和-这个图的最大流,即报酬总和去掉 报酬填补费用的总和 ,就是净收益
我们如何比较感性地理解它呢
求最大流的过程,可以看成用实验的钱消去仪器的钱的过程
而有一些实验可能先被遍历到,而这次实验的报酬小于所需仪器的总花费,即这次实验有点亏,但买了给其他实验用的仪器,而其他实验可以把这些钱补回来
在图上的体现就是,有其他实验的流量沿着反向边流向了这次实验
通过求最小割,我们把图分割成了两块,一块包含源点,一块包含汇点
源点指向的每个联通块中,都至少存在一个点,源点向它的流量$>0$,那么这个联通块里的实验仪器组合才是获利的
那么最终答案就是总获利-最大流,方案就是再进行一次$bfs$,$dep$有值的点,即和源点在同一联通块里的点。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #define N1 350 6 #define M1 3010 7 #define ll long long 8 #define dd double 9 #define inf 0x3f3f3f3f 10 using namespace std; 11 12 int gint() 13 { 14 int ret=0,fh=1;char c=getchar(); 15 while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();} 16 while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();} 17 return ret*fh; 18 } 19 20 int n,m,nm,S,T; 21 int p[N1],c[N1]; 22 struct Edge{ 23 int head[N1],to[M1<<1],nxt[M1<<1],flow[M1<<1],cte; 24 void ae(int u,int v,int F) 25 { 26 cte++; to[cte]=v; flow[cte]=F; 27 nxt[cte]=head[u]; head[u]=cte; 28 } 29 }e; 30 31 int que[M1],hd,tl,dep[N1],cur[N1]; 32 int bfs(Edge &E) 33 { 34 int x,j,v; 35 memset(dep,-1,sizeof(dep)); memcpy(cur,E.head,sizeof(cur)); 36 hd=1,tl=0; que[++tl]=S; dep[S]=0; 37 while(hd<=tl) 38 { 39 x=que[hd++]; 40 for(j=E.head[x];j;j=E.nxt[j]) 41 { 42 v=E.to[j]; if(dep[v]!=-1||!E.flow[j]) continue; 43 dep[v]=dep[x]+1; que[++tl]=v; 44 } 45 } 46 return dep[T]!=-1; 47 } 48 int dfs(Edge &E,int x,int limit) 49 { 50 int j,v,flow,ans=0; if(x==T||!limit) return limit; 51 for(j=cur[x];j;j=E.nxt[j]) 52 { 53 cur[x]=j; v=E.to[j]; 54 if( dep[v]==dep[x]+1 && (flow=dfs(E,v,min(E.flow[j],limit))) ) 55 { 56 limit-=flow; ans+=flow; 57 E.flow[j]-=flow; E.flow[j^1]+=flow; 58 if(!limit) break; 59 } 60 } 61 return ans; 62 } 63 int use[N1],de; 64 void Dinic() 65 { 66 int mxflow=0,x,j,v,i,flag,sum=0; 67 for(i=1;i<=m;i++) sum+=p[i]; 68 while(bfs(e)) mxflow+=dfs(e,S,inf); 69 bfs(e); 70 for(i=1;i<=m;i++) if(dep[i]!=-1) printf("%d ",i); puts(""); 71 for(i=m+1;i<=m+n;i++) if(dep[i]!=-1) printf("%d ",i-m); puts(""); 72 printf("%d\n",sum-mxflow); 73 } 74 75 char str[1000]; 76 int main() 77 { 78 scanf("%d%d",&m,&n); 79 int i,j,x,y,flag,slen; S=m+n+1,T=m+n+2; e.cte=1; 80 for(i=1,slen=0;i<=m;i++) 81 { 82 p[i]=gint(); e.ae(S,i,p[i]), e.ae(i,S,0); 83 memset(str,0,sizeof(str)); cin.getline(str,1000); slen=0; 84 while(sscanf(str+slen,"%d",&x)==1) 85 { 86 e.ae(i,x+m,inf); e.ae(x+m,i,0); 87 if(!x) slen++; 88 else{ while(x) x/=10,slen++;} 89 slen++; 90 } 91 } 92 for(i=m+1;i<=m+n;i++) c[i]=gint(), e.ae(i,T,c[i]), e.ae(T,i,0); 93 Dinic(); 94 return 0; 95 }