[网络流24题]太空飞行计划问题

题目描述

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

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

题解

同样需要Ford-Fulkerson定理

源点向实验连容量为奖金的钱,实验向仪器连容量无限的边,仪器向汇点连容量为花费的边

答案同样是总奖金-最小割

  1 #include<queue>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define INF 0x3f3f3f3f
  6 using namespace std;
  7 int n,m,cnt,tot,tmp;
  8 int st,ed,ans,tp1,tp2;
  9 char usd;
 10 int stmt[205];
 11 bool used[205];
 12 int inst[205];
 13 bool vis[205];
 14 int cst[205];
 15 int pay[205];
 16 int dis[205];
 17 int head[205];
 18 struct Edge{
 19     int fr;
 20     int to;
 21     int flw;
 22     int nxt;
 23 }edge[10005],pth[10005];
 24 void init(){
 25     memset(head,-1,sizeof(head));
 26 }
 27 void addedge(int u,int v,int f){
 28     edge[cnt].fr=u;
 29     edge[cnt].to=v;
 30     edge[cnt].flw=f;
 31     edge[cnt].nxt=head[u];
 32     head[u]=cnt++;
 33     edge[cnt].fr=v;
 34     edge[cnt].to=u;
 35     edge[cnt].nxt=head[v];
 36     head[v]=cnt++;
 37 }
 38 int bfs(int ban){
 39     queue<int>que;
 40     memset(dis,0x3f,sizeof(dis));
 41     que.push(st);dis[st]=0;
 42     while(!que.empty()){
 43         int u=que.front();
 44         que.pop();
 45         for(int i=head[u];i!=-1;i=edge[i].nxt){
 46             int v=edge[i].to;
 47             if(!edge[i].flw||v==ban)continue;
 48             if(dis[v]==0x3f3f3f3f){
 49                 dis[v]=dis[u]+1;
 50                 que.push(v);
 51             }
 52         }
 53     }
 54     return (dis[ed]!=0x3f3f3f3f);
 55 }
 56 int dfs(int u,int flw,int ban){
 57     if(u==ed)return flw;
 58     int All=0;int f;
 59     for(int i=head[u];i!=-1;i=edge[i].nxt){
 60         int v=edge[i].to;
 61         if(dis[v]!=dis[u]+1)continue;
 62         if((f=dfs(v,min(flw,edge[i].flw),ban))>0){
 63             edge[i].flw-=f;
 64             edge[i^1].flw+=f;
 65             flw-=f;All+=f;
 66             if(!flw)break;
 67         }
 68     }
 69     return All;
 70 }
 71 void dinic(int ban){
 72     tmp=0;
 73     memcpy(edge,pth,sizeof(edge));
 74     while(bfs(ban)){
 75         tmp+=dfs(st,INF,ban);
 76     }
 77 }
 78 int main(){
 79     init();
 80     scanf("%d%d",&m,&n);ed=n+m+1;
 81     for(int i=1;i<=m;i++){
 82         scanf("%d",&pay[i]);tot+=pay[i];
 83         usd=getchar();int tl=0;
 84         while(usd!='\n'&&usd!='\r'){
 85             if(usd==' '&&tl){
 86                 addedge(i,tl+m,INF);
 87                 tl=0;usd=getchar();
 88                 continue;
 89             }
 90             if(usd>='0')tl=tl*10+usd-'0';
 91             usd=getchar();
 92         }
 93         if(tl)addedge(i,tl+m,INF);
 94         addedge(st,i,pay[i]);
 95     }
 96     for(int i=1;i<=n;i++){
 97         scanf("%d",&cst[i]);
 98         addedge(i+m,ed,cst[i]);
 99     }
100     memcpy(pth,edge,sizeof(pth));
101     dinic(-1);ans=tmp;
102     for(int i=1;i<=n;i++){
103         dinic(i+m);
104         if(tmp+cst[i]==ans){
105             inst[++tp1]=i;
106             used[i]=true;
107         }
108     }
109     for(int i=1;i<=m;i++){
110         int fl=0;
111         for(int j=head[i];j!=-1;j=edge[j].nxt){
112             int v=edge[j].to;
113             if(!v)continue;
114             if(!used[v-m]){
115                 fl=1;
116                 break;
117             }
118         }
119         if(!fl)stmt[++tp2]=i;
120     }
121     sort(stmt+1,stmt+tp2+1);
122     sort(inst+1,inst+tp1+1);
123     for(int i=1;i<=tp2;i++){
124         printf("%d",stmt[i]);
125         if(i!=tp2)printf(" ");
126     }printf("\n");
127     for(int i=1;i<=tp1;i++){
128         printf("%d",inst[i]);
129         if(i!=tp1)printf(" ");
130     }printf("\n");ans=tot-ans;
131     printf("%d\n",ans);
132     return 0;
133 }

 

posted @ 2018-12-17 13:28  Mr_Handsome  阅读(181)  评论(0编辑  收藏  举报