网络流二十四题之二 —— 太空飞行计划问题(SHUT)

太空飞行计划问题

Description

W 教授正在为国家航天中心计划一系列的太空飞行。
每次太空飞行可进行一系列商业性实验而获取利润。
现已确定了一个可供选择的实验集合
E={E1,E2,,Em}
和进行这些实验需要使用的全部仪器的集合
I={I1,I2,,In}
实验 Ej 需要用到的仪器是 I 的子集 Rj 。配置仪器 Ik的费用为 ck美元。
实验 Ej 的赞助商已同意为该实验结果支付 pj 美元。
W 教授的任务是找出一个有效算法,确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的净收益最大。
这里净收益是指进行实验所获得的全部收入与配置仪器的全部费用的差额。

对于给定的实验和仪器配置情况,编程找出净收益最大的试验计划。

Input

1 行有 2 个正整数 m n
m 是实验数, n 是仪器数。
接下来的 m 行,每行是一个实验的有关数据。
第一个数赞助商同意支付该实验的费用;
接着是该实验需要用到的若干仪器的编号。
最后一行的 n 个数是配置每个仪器的费用。

Output

1 行是实验编号;
2 行是仪器编号;
最后一行是净收益。

Sample Input

2 3
10 1 2
25 2 3
5 6 7

Sample Output

1 2
1 2 3
17

HINT

数据范围很小啦

Solution

因为是网络流里面的题,所以肯定要用网络流来做了啊。
弄个源点和一个汇点。
将源点连接每个实验,流量为实验的收益。
将每个仪器连接汇点,流量为装置的花费。
∵ 净收益=选择的实验的收益-选择的装置的花费。
∴ 净收益=(所有实验的收益-未选择的实验的收益)-选择的装置的花费。
即净收益=所有实验的收益-(未选择的实验的收益+选择的装置的花费(②))。
∵ 所有实验的收益是以给固定的值,所以我们只要使 ② 最小即可。

对应到网络中,我们发现 ② 正好是网络的一个割。
所以只要求最小割就行了。

Code

[cpp]
  1. #include <iostream>  
  2. #include <cstdio>  
  3. #include <cstring>  
  4. #include <queue>  
  5.   
  6. #define Min(x,y) ((x)<(y)?(x):(y))  
  7.   
  8. using namespace std;  
  9.   
  10. const int INF=0x3f3f3f3f;  
  11.   
  12. int m,n,l,s,t,cnt;  
  13.   
  14. int low[1000],head[100],nxt[1000],data[1000];  
  15. int w[100];  
  16. int c[100];  
  17. int to[100][100];   
  18. int dis[100];  
  19.    
  20. char str[10000];  
  21. queue<int>q;  
  22.   
  23. void add(int x,int y,int z){  
  24.     nxt[cnt]=head[x];data[cnt]=y;low[cnt]=z;head[x]=cnt++;  
  25.     nxt[cnt]=head[y];data[cnt]=x;low[cnt]=0;head[y]=cnt++;   
  26. }  
  27.   
  28. bool BFS(){  
  29.     memset(dis,-1,sizeof dis);  
  30.     q.push(s);dis[s]=0;  
  31.     while(!q.empty()){  
  32.         int now=q.front();q.pop();  
  33.         for(int i=head[now];i!=-1;i=nxt[i])  
  34.             if(low[i]&&dis[data[i]]<0){dis[data[i]]=dis[now]+1;q.push(data[i]);}  
  35.     }  
  36.     return dis[t]>0;  
  37. }  
  38.   
  39. int dfs(int now,int flow){  
  40.     if(now==t)return flow;  
  41.     int Flow;  
  42.     for(int i=head[now];i!=-1;i=nxt[i]){  
  43.         if(low[i]&&dis[data[i]]==dis[now]+1){  
  44.             if(Flow=dfs(data[i],Min(flow,low[i]))){  
  45.                 low[i]-=Flow;  
  46.                 low[i^1]+=Flow;  
  47.                 return Flow;  
  48.             }  
  49.         }  
  50.     }  
  51.     return 0;  
  52. }  
  53.   
  54. int main(){  
  55.     int weight=0;  
  56.     scanf(”%d%d”,&m,&n);  
  57.     memset(head,-1,sizeof head);  
  58.     s=n+m+1,t=n+m+2;  
  59.     for(int i=1;i<=m;i++){  
  60.         scanf(”%d”,&w[i]);  
  61.         weight+=w[i];  
  62.         gets(str);  
  63.         l=strlen(str);  
  64.         int pos=0;  
  65.         while(pos<l){  
  66.             if(str[pos]<‘0’||str[pos]>‘9’){  
  67.                 while(str[pos]<‘0’||str[pos]>‘9’&&pos<l){pos++;}  
  68.                 if(pos==l)break;  
  69.                 to[i][0]++;  
  70.             }  
  71.             to[i][to[i][0]]=to[i][to[i][0]]*10+str[pos]-’0’;  
  72.             pos++;  
  73.         }  
  74.     }  
  75.     for(int i=1;i<=m;i++){  
  76.         add(s,i,w[i]);  
  77.         for(int j=1;j<=to[i][0];j++)add(i,to[i][j]+m,INF);  
  78.     }  
  79.     for(int i=1;i<=n;i++){  
  80.         scanf(”%d”,&c[i]);  
  81.         add(i+m,t,c[i]);  
  82.     }  
  83.     while(BFS()){  
  84.         int flag;  
  85.         while(flag=dfs(s,INF)){  
  86.             weight-=flag;  
  87.         }  
  88.     }  
  89.     BFS();  
  90.     for(int i=1;i<=m;i++)if(dis[i]>0)printf(“%d ”,i);  
  91.     printf(”\n”);   
  92.     for(int j=m+1;j<=m+n;j++)if(dis[j]>0)printf(“%d ”,j-m);  
  93.     printf(”\n%d\n”,weight);  
  94.     return 0;  
  95. }  

你可能感兴趣的:(网络流二十四题之二 —— 太空飞行计划问题(SHUT))