【网络流24题】 No.2 太空飞行计划问题 (最大闭合权图 最大流 )
原题:W教授正在为国家航天中心计划一系列的太空飞行。每次太空飞行可进行一系列商业性实验而获取利润。现已确定了一个可供选择的实验集合 E={E1,E2,...,Em},和进行这些实验需要使用的全部仪器的集合 I={I1,I2,...,In}。实验 Ej 需要用到的仪器是 I 的子集 RjÍI。配置仪器 Ik 的费用为 ck 美元。实验 Ej 的赞助商已同意为该实验结果支付 pj 美元。W 教授的任务是找出一个有效算法,确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的净收益最大。这里净收益是指进行实验所获得的全部收入与配置仪器的全部费用的差额。输入说明文件第 1 行有 2 个正整数 m 和 n。 m 是实验数, n 是仪
器数。 接下来的 m 行,每行是一个实验的有关数据。 第一个数赞助商同意支付该实验的费
用;接着是该实验需要用到的若干仪器的编号。最后一行的 n 个数是配置每个仪器的费用。input2 3
10 1 2
25 2 3
5 6 7output1 2
1 2 3
17
【分析】
就是一个裸的最大权闭合子图啦。
但是输出方案让我很内伤。。。
上一题是点数尽量少,这一题是尽量多。。。
就是一些又不赚钱又不赔钱的也要算上。
但是跑最大流的话,会把他割掉,然后dfs方法就不行了,内伤、、、
纠结了好久
网上有人说那就枚举把。。。
但是,我转念一想,不如猥琐一遍,,,然后我就放大边权,,,过了!!!!
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 using namespace std; 8 #define Maxn 110 9 #define INF 0xfffffff 10 11 struct node 12 { 13 int x,y,f,o,next; 14 }t[Maxn*Maxn];int len; 15 int first[Maxn]; 16 17 int mymin(int x,int y) {return x<y?x:y;} 18 19 void ins(int x,int y,int f) 20 { 21 t[++len].x=x;t[len].y=y;t[len].f=f; 22 t[len].next=first[x];first[x]=len;t[len].o=len+1; 23 t[++len].x=y;t[len].y=x;t[len].f=0; 24 t[len].next=first[y];first[y]=len;t[len].o=len-1; 25 } 26 27 int c[Maxn]; 28 29 int st,ed; 30 31 queue<int > q; 32 int dis[Maxn]; 33 bool bfs() 34 { 35 while(!q.empty()) q.pop(); 36 memset(dis,-1,sizeof(dis)); 37 q.push(st);dis[st]=0; 38 while(!q.empty()) 39 { 40 int x=q.front(); 41 for(int i=first[x];i;i=t[i].next) if(t[i].f>0) 42 { 43 int y=t[i].y; 44 if(dis[y]==-1) 45 { 46 dis[y]=dis[x]+1; 47 q.push(y); 48 } 49 } 50 q.pop(); 51 } 52 if(dis[ed]==-1) return 0; 53 return 1; 54 } 55 56 int ffind(int x,int flow) 57 { 58 if(x==ed) return flow; 59 int now=0; 60 for(int i=first[x];i;i=t[i].next) if(t[i].f>0) 61 { 62 int y=t[i].y; 63 if(dis[y]==dis[x]+1) 64 { 65 int a=ffind(y,mymin(flow-now,t[i].f)); 66 t[i].f-=a; 67 t[t[i].o].f+=a; 68 now+=a; 69 } 70 if(now==flow) break; 71 } 72 if(now==0) dis[x]=-1; 73 return now; 74 } 75 76 int max_flow() 77 { 78 int ans=0; 79 while(bfs()) 80 { 81 ans+=ffind(st,INF); 82 } 83 return ans; 84 } 85 86 bool qq[Maxn]; 87 88 void dfs(int x) 89 { 90 qq[x]=1; 91 for(int i=first[x];i;i=t[i].next) if(!qq[t[i].y]&&t[i].f>0) 92 { 93 dfs(t[i].y); 94 } 95 } 96 97 int main() 98 { 99 int m,n,sum=0; 100 scanf("%d%d",&m,&n); 101 len=0; 102 memset(first,0,sizeof(first)); 103 for(int i=1;i<=m;i++) 104 { 105 scanf("%d",&c[i]); 106 sum+=c[i]; 107 while(1) 108 { 109 int x; 110 scanf("%d",&x); 111 if(x==-1) break; 112 ins(i,x+m,INF); 113 } 114 } 115 st=n+m+1;ed=st+1; 116 for(int i=1;i<=m;i++) ins(st,i,c[i]*10000+1); 117 for(int i=1;i<=n;i++) 118 { 119 int x; 120 scanf("%d",&x); 121 ins(i+m,ed,x*10000); 122 } 123 int x=max_flow(); 124 memset(qq,0,sizeof(qq)); 125 dfs(st); 126 /*for(int i=1;i<=len;i+=2) 127 { 128 if(t[i].x==st&&t[i].f>0) qq[t[i].y]=1; 129 if(t[i].y==ed&&t[i].f==0) 130 qq[t[i].x]=1; 131 }*/ 132 for(int i=1;i<=m;i++) if(qq[i]) printf("%d ",i);printf("\n"); 133 for(int i=m+1;i<=m+n;i++) if(qq[i]) printf("%d ",i-m);printf("\n"); 134 printf("%d\n",sum-x/10000); 135 return 0; 136 }
那啥*10000就是方大边权。。。ORZ。。。
2016-11-04 09:42:22