• [网络流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("
    ");
    	for(int i=m+1;i<=T;++i) if(vis[i]) printf("%d ",i-m);
    	printf("
    %d
    ",sumv-Ans);
    }
    
    int main(){
        Init();
    	SAP();
    	print();
    	return 0;
    } 
    
  • 相关阅读:
    图论基础
    排序二叉树的中序遍历
    先序遍历序列和中序遍历序列,输出该二叉树的后序遍历序列
    数据结构实验之 二叉树的建立与遍历
    c++ 头文件 及 sort 和 vector简单介绍
    最短路径(Floyd 模板题)
    最小生成树(kruskal模版 模板)
    基于邻接矩阵的广度优先搜索遍历(BFS)
    [SCOI2015]国旗计划
    [HNOI2015]开店
  • 原文地址:https://www.cnblogs.com/void-f/p/8289641.html
Copyright © 2020-2023  润新知