太空飞行计划问题
W 教授正在为国家航天中心计划一系列的太空飞行。每次太空飞行可进行一系列商业
性实验而获取利润。现已确定了一个可供选择的实验集合 E={E1,E2,…,Em},和进行这
些实验需要使用的全部仪器的集合I={I1, I2,…In}。 实验 Ej需要用到的仪器是 I的子集 RjÍI。
配置仪器Ik的费用为Ck美元。实验Ej的赞助商已同意为该实验结果支付Pj美元。W教授的
任务是找出一个有效算法, 确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才
能使太空飞行的净收益最大。这里净收益是指进行实验所获得的全部收入与配置仪器的全部
费用的差额。
´编程任务:
对于给定的实验和仪器配置情况,编程找出净收益最大的试验计划。
性实验而获取利润。现已确定了一个可供选择的实验集合 E={E1,E2,…,Em},和进行这
些实验需要使用的全部仪器的集合I={I1, I2,…In}。 实验 Ej需要用到的仪器是 I的子集 RjÍI。
配置仪器Ik的费用为Ck美元。实验Ej的赞助商已同意为该实验结果支付Pj美元。W教授的
任务是找出一个有效算法, 确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才
能使太空飞行的净收益最大。这里净收益是指进行实验所获得的全部收入与配置仪器的全部
费用的差额。
´编程任务:
对于给定的实验和仪器配置情况,编程找出净收益最大的试验计划。
Input
第 1行有 2 个正整数 m和 n。m是实验数,n是仪
器数。接下来的 m 行,每行是一个实验的有关数据。第一个数赞助商同意支付该实验的费
用;接着是该实验需要用到的若干仪器的编号。最后一行的 n个数是配置每个仪器的费用。
器数。接下来的 m 行,每行是一个实验的有关数据。第一个数赞助商同意支付该实验的费
用;接着是该实验需要用到的若干仪器的编号。最后一行的 n个数是配置每个仪器的费用。
Output
程序运行结束时,将最佳实验方案输出。第 1 行是实验编号;第 2
行是仪器编号;最后一行是净收益。
行是仪器编号;最后一行是净收益。
-----------------------------------------------------------------------------------
正解=网络流
设Sum为金钱和
题目所求相当于 求Sum(所做实验)-Sum(所需仪器)
既 Total(所有实验)-Sum(不做的实验)-Sum(所需仪器)
所以只需求出 Sum(不做的实验)+Sum(所需仪器)的最小值
考虑网络流:
构图:
将 实验Xi 于 仪器Yi 分成2个集合
若实验 Xi 需要 仪器Yj 则在 i j 间连一条流量为无限的边
将 源点S 连向所有实验流量为实验利润
将所有仪器连向 汇点T 流量为运输费用
证明:
考虑一个仪器对应一个实验
割仪器表示所这个实验应减掉仪器的钱
割实验表示不做这个实验应减掉这个实验的钱
- =
如果一个实验要做则它所需的仪器都应属于Sum(所需仪器)
既当Xi存在网络中时它所需的仪器都不能存在于网络中
既不存在从 S 到 T 的流为合法情况
且需要Sum(不做的实验)+Sum(所需仪器)最小
既求最小割- =
代码如下:
1 #include<cstdio> 2 #include<algorithm> 3 #include<string> 4 #include<cstring> 5 #include<iostream> 6 #include<cmath> 7 #define LL long long 8 #define INF 999999999 9 #define Min(num1,num2) if(num1>num2) num1=num2 10 #define Max(num1,num2) if(num1<num2) num1=num2 11 #define N 100100 12 //using namespace std ; 13 int next[N],last[N],flow[N],to[N],op[N],G; 14 int Total,n,m,ans,nodes,S,T,dis[N],cnt[N]; 15 bool vis[N]; 16 void addedge(int x,int y,int v){ 17 next[++G]=last[x]; last[x]=G; flow[G]=v; to[G]=y; op[G]=G+1; 18 next[++G]=last[y]; last[y]=G; flow[G]=0; to[G]=x; op[G]=G-1; 19 } 20 int sap(int t,int delta){ 21 if(t==T) return delta; 22 int sum=0,mindis=nodes; 23 for(int i=last[t]; i ;i=next[i]){ 24 if(flow[i]>0 && dis[to[i]]+1==dis[t]){ 25 int save = sap(to[i],std::min(flow[i],delta-sum)); 26 sum += save; 27 flow[ i ] -= save; 28 flow[op[i]] += save; 29 if (dis[S]>=nodes||sum==delta) return sum; 30 } 31 if(flow[i]>0) Min(mindis,dis[to[i]]); 32 } 33 if(sum==0){ 34 if(!--cnt[dis[t]]) dis[S]=nodes; 35 else ++cnt[dis[t]=mindis+1]; 36 } 37 return sum; 38 } 39 void DFS(int t){ 40 for(int i=last[t];i;i=next[i]) 41 if(!vis[to[i]]&&flow[i]){ 42 vis[to[i]]=1; 43 DFS(to[i]); 44 } 45 } 46 int main(){ 47 scanf("%d%d",&m,&n); 48 S=0; 49 T=m+n+1; 50 for(int x,y,i=1;i<=m;i++){ 51 char flag; 52 scanf("%d%c",&x,&flag); 53 addedge(S,i,x); 54 Total+=x; 55 while(flag!='\n'){ 56 scanf("%d%c",&y,&flag); 57 addedge(i,y+m,INF); 58 } 59 } 60 for(int x,i=1;i<=n;i++){ 61 scanf("%d",&x); 62 addedge(i+m,T,x); 63 } 64 nodes=cnt[0]=T+1; 65 while(nodes>dis[S]) ans+=sap(S,INF); 66 DFS(S); 67 bool use=false ; 68 for(int i=1;i<=m;i++) 69 if(vis[i]){ 70 if(use) printf(" "); 71 printf("%d",i); 72 use=1; 73 } 74 use=false ; 75 printf("\n"); 76 for(int i=m+1;i<=n+m;i++) 77 if(vis[i]){ 78 if(use) printf(" "); 79 printf("%d",i-m); 80 use=1; 81 } 82 printf("\n%d",Total-ans); 83 }