zoukankan      html  css  js  c++  java
  • [网络流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;
    } 
    
  • 相关阅读:
    JDBC 删除数据两种方式,PreparedStatement表示预编译的 SQL 语句的对象,防止sql注入
    MySQL 主键外键
    JDBC 增删改查
    MySQL数据库语句
    反射
    如何安装、配置、登陆MySQL
    如何干净卸除MySQL数据库
    IO流总结
    字符流五种读写 字符流 BufferedWriter BufferedReader 带缓冲区的字符流
    单例模式
  • 原文地址:https://www.cnblogs.com/void-f/p/8289641.html
Copyright © 2011-2022 走看看