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

Description

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

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

Code

这题是最大权闭合图,经过某论文的充分证明,即求最小割,转为求最大流,然后用实验总收益减去最大流就是答案了

输方案的话,只要找非最大流路径的边就行了,即残量网络中流量>0的路径为所求

#include <cstdio>
#include <algorithm>
#include <cstring>
#define Inf 0x7fffffff
using namespace std;

struct info{
	int nex,to,f;
}e[6000];
int n,m,tot,head[6000],S,T,sumv,nodes,Ans,cnt[200],dis[200];
bool vis[200];

void Link(int u,int v,int f){
	e[++tot].to=v;e[tot].f=f;e[tot].nex=head[u];head[u]=tot;
	e[++tot].to=u;e[tot].f=0;e[tot].nex=head[v];head[v]=tot;
}

int sap(int u,int d){
	if(u==T) return d;
	int sum=0,mins=nodes;
	
	for(int i=head[u];i;i=e[i].nex){
		int v=e[i].to;
		if(e[i].f>0&&dis[u]==dis[v]+1){
			int save=sap(v,min(d-sum,e[i].f));
			sum+=save;
			e[i].f-=save;
			e[i^1].f+=save;
			if(dis[S]>=nodes||sum==d) return sum;
		}
		if(e[i].f>0) mins=min(mins,dis[v]);
	}
	if(!sum){
		if(!(--cnt[dis[u]])) dis[S]=nodes;
		else ++cnt[dis[u]=mins+1];
	}
	return sum;
}

void SAP(){
	cnt[0]=nodes;
	while(dis[S]<nodes) Ans+=sap(S,Inf);
}

void Init(){
	scanf("%d%d",&m,&n);
	S=0,T=m+n+1,nodes=m+n+2,tot=1;
	for(int i=1,t;i<=m;++i){
		scanf("%d",&t);
		sumv+=t;
		Link(S,i,t);		
		for(;;){
			char ch;
			while((ch=getchar())==' ');
			ungetc(ch,stdin);
			if(ch==10||ch==13) break;
			scanf("%d",&t);
			Link(i,m+t,Inf);
		}
	}
	for(int i=1,t;i<=n;++i){
		scanf("%d",&t);
		Link(m+i,T,t);
	}
}


void dfs(int u){
	vis[u]=1;
	for(int i=head[u];i;i=e[i].nex)
		if(!vis[e[i].to]&&e[i].f) dfs(e[i].to);
}

void print(){
	dfs(S);
	for(int i=1;i<=m;++i) if(vis[i]) printf("%d ",i);
	printf("\n");
	for(int i=m+1;i<=T;++i) if(vis[i]) printf("%d ",i-m);
	printf("\n%d\n",sumv-Ans);
}

int main(){
    Init();
	SAP();
	print();
	return 0;
} 
posted @ 2018-01-15 19:51  void_f  阅读(120)  评论(0编辑  收藏  举报