• [ZJOI2010]网络扩容


    题目:BZOJ1834、洛谷P2604、codevs1362。

    题目大意:给你一些边的容量和将这条边扩充1点容量的费用,求1.点1到n的最大流;2.将最大流扩充k点的最小费用。

    解题思路:第一问就是裸最大流。

    第二问可以这么做:将原图容量改成INF,超级源点S连容量k费用0的边到1,从n连容量k费用0的边到超级汇点。然后对该图求最小费用最大流就是答案。

    因为扩容k并不用考虑原图,只要保证源点到汇点能有k的流量即可,那么此时求最小费用最大流即可。

    不过有一点,在第一问跑完最大流后,会剩下一些边,这些边是免费的,所以在考虑第二问的时候,应该在第一问的残余网络上建图。

    所以我在求第一问时用的也是费用流,费用是0,然后我们只需要最后的流量即可。接着直接在该图上建新图然后跑最大流即可。

    EK过。

    C++ Code:

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<queue>
    using namespace std;
    #define min(a,b) (((a)<(b))?(a):(b))
    #define C c=getchar()
    #define INF 0x3f3f3f3f
    struct edges{
    	int from,to,cap,cost,nxt;
    }e[500005];
    int n,m,k,cnt,head[5005],vis[5005],dis[5005],pre_e[5005],a[5005];
    int u[5005],v[5005],cap[5005],Cost[5005];
    queue<int>q;
    inline int readint(){
    	char C;
    	int p=0;
    	for(;!isdigit(c);C);
    	for(;isdigit(c);C)p=(p<<3)+(p<<1)+(c^'0');
    	return p;
    }
    inline void addedge(int from,int to,int cap,int cost){
    	e[++cnt]=(edges){from,to,cap,cost,head[from]};
    	head[from]=cnt;
    	e[++cnt]=(edges){to,from,0,-cost,head[to]};
    	head[to]=cnt;
    }
    void SPFA(int s,int t,int& flow,int& cost){
    	for(;;){
    		memset(vis,0,sizeof vis);
    		memset(dis,0x3f,sizeof dis);
    		memset(pre_e,0,sizeof pre_e);
    		memset(a,0x3f,sizeof a);
    		vis[s]=1;
    		dis[s]=0;
    		q.push(s);
    		while(!q.empty()){
    			int u=q.front();
    			q.pop();
    			vis[u]=0;
    			for(int i=head[u];i;i=e[i].nxt){
    				int v=e[i].to;
    				if(dis[v]>dis[u]+e[i].cost&&e[i].cap>0){
    					dis[v]=dis[u]+e[i].cost;
    					pre_e[v]=i;
    					a[v]=min(a[u],e[i].cap);
    					if(!vis[v]){
    						vis[v]=1;
    						q.push(v);
    					}
    				}
    			}
    		}
    		if(dis[t]==INF)return;
    		flow+=a[t];
    		cost+=a[t]*dis[t];
    		for(int i=t;i!=s;i=e[pre_e[i]].from){
    			e[pre_e[i]].cap-=a[t];
    			e[pre_e[i]^1].cap+=a[t];
    		}
    	}
    }
    int main(){
    	n=readint(),m=readint(),k=readint();
    	cnt=1;
    	memset(head,0,sizeof head);
    	for(int i=1;i<=m;++i){
    		u[i]=readint(),v[i]=readint(),cap[i]=readint(),Cost[i]=readint();
    		addedge(u[i],v[i],cap[i],0);
    	}
    	int flow=0,cost=0;
    	SPFA(1,n,flow,cost);
    	printf("%d ",flow);
    	for(int i=1;i<=m;++i)addedge(u[i],v[i],INF,Cost[i]);
    	addedge(0,1,k,0);
    	addedge(n,n+1,k,0);
    	flow=0,cost=0;
    	SPFA(0,n+1,flow,cost);
    	printf("%d
    ",cost);
    	return 0;
    }
    
  • 相关阅读:
    【MongoDB初识】-结合C#简单使用,驱动2.x
    【NuGet】打包上传一条龙服务
    【NuGet】搭建自己团队或公司的NuGet
    【MongoDB初识】-其他操作
    【MongoDB初识】-条件操作符
    【MongoDB初识】-增删改
    【MongoDB初识】-安装篇
    【面试题】-100盏灯
    【微信开发】一获取用户授权(静默授权方式)
    XML序列化及反序列化
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/7612519.html
Copyright © 2020-2023  润新知