太空飞行计划问题

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个数是配置每个仪器的费用。 

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 }
View Code

 

posted @ 2013-11-20 16:59  Mr. Black  阅读(312)  评论(2编辑  收藏  举报