【网络流24题】太空飞行计划问题

问题描述

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

数据输入

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

结果输出

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

输入样例

2 3
10 1 2
25 2 3
5 6 7

输出样例

1 2
1 2 3
17

限制

1<=n,m<=50

时间:1S

空间:256MB

题解

https://www.cnblogs.com/zhenghaotian/p/6929083.html

https://yq.aliyun.com/ziliao/290204

http://www.cnblogs.com/wuyiqi/archive/2012/03/12/2391960.html

残量网络中和源点连通的点的集合(不包括源点)即为选中的

#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
const int N=150,M=50*50*4+105,inf=1047483647;
int n,m,s=101,t=102,ans;
int num=1,last[N],nxt[M],ver[M],c[M];
inline void add(int x,int y,int z)
 {nxt[++num]=last[x]; last[x]=num; ver[num]=y; c[num]=z;
  nxt[++num]=last[y]; last[y]=num; ver[num]=x; c[num]=0;
 }

queue<int> q;int d[N],cur[N]; 

inline bool bfs()
 {memset(d,0,sizeof(d));
  while(!q.empty()) q.pop();
  q.push(s); d[s]=1;
  for(int i=1;i<=110;i++) cur[i]=last[i];
  
  while(!q.empty())
   {int x=q.front(); q.pop();
   
    for(int i=last[x],y;i;i=nxt[i])
     {if(!d[y=ver[i]] && c[i])
       d[y]=d[x]+1,q.push(y);
     }
   }
  return d[t]>0;  
 }

int dfs(int x,int flow)
 {if(x==t) return flow;
  int rest=flow;
  for(int i=cur[x],y;i && rest;i=nxt[i])
   {cur[x]=i; y=ver[i]; 
    if(d[y]==d[x]+1 && c[i])
      {int f=dfs(y,min(c[i],rest));
       if(f==0) d[y]=0;
       c[i]-=f; c[i^1]+=f;
       rest-=f;
      }
   }
  return flow-rest; 
 }
inline bool read(int &re) 
{  re=0; char ch = getchar();
   while (!('0'<= ch && ch<='9')) { if(ch == '\n') return 0; ch=getchar(); }
   while ('0'<= ch && ch<='9')  { re=re*10+ch-'0'; ch=getchar(); }
   return ch!='\n';
}

int main()
{
 scanf("%d%d",&m,&n); int r;		
 for(int i=1;i<=m;i++)	
	{scanf("%d",&r); ans+=r;
	 add(s,i,r);
	 while(read(r)) {add(i,r+50,inf);}
	 add(i,r+50,inf);
	}
	
 for(int i=1;i<=n;i++){scanf("%d",&r); add(i+50,t,r);}		
	
 while(bfs())
   while(int flow=dfs(s,inf))	ans-=flow;
	
 for(int i=1;i<=m;i++) if(d[i]) printf("%d ",i);
 printf("\n");
 for(int i=1;i<=n;i++) if(d[i+50]) printf("%d ",i); 
 	
 printf("\n%d",ans);	
return 0;
}

 

转载于:https://www.cnblogs.com/YuXiaoze/p/10679503.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值