太空飞行计划问题

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

 

你可能感兴趣的:(问题)