zoukankan      html  css  js  c++  java
  • 费用流学习笔记

    费用流学习笔记

    最小/最大费用最大流

    每一条边不仅有流量还有费用的限制

    要满足流量最大的前提下费用尽可能小/大

    增广的时候选择费用的最短路/最长路增广就行了

    建边的时候反向边的流量为 (0),费用变为相反数

    因为费用有可能为负数,所以要拿 (spfa) 预处理出最短路/最长路

    如果写法是 (EK) 单路增广的话需要一个 (pre) 数组来记录最短路/最长路是从哪里转移来的

    如果是 (dinic) 多路增广则要注意在 (dfs) 的时候给每一个点打上一个 (vis) 标记,否则会在总费用为 (0) 的环中死循环

    代码(EK)

    #include<cstdio>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<cstring>
    #define rg register
    inline int read(){
    	rg int x=0,fh=1;
    	rg char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    const int maxn=1e5+5;
    int h[maxn],tot=2,s,t,n,m;
    struct asd{
    	int to,nxt,val,cost;
    }b[maxn<<1];
    void ad(rg int aa,rg int bb,rg int cc,rg int dd){
    	b[tot].to=bb;
    	b[tot].nxt=h[aa];
    	b[tot].val=cc;
    	b[tot].cost=dd;
    	h[aa]=tot++;
    }
    int dis[maxn],incf[maxn],pre[maxn];
    bool inq[maxn];
    std::queue<int> q;
    bool spfa(){
    	memset(dis,0x3f,sizeof(dis));
    	memset(incf,0,sizeof(incf));
    	incf[s]=0x3f3f3f3f;
    	dis[s]=0;
    	q.push(s);
    	inq[s]=1;
    	while(!q.empty()){
    		rg int now=q.front();
    		q.pop();
    		inq[now]=0;
    		for(rg int i=h[now];i!=-1;i=b[i].nxt){
    			rg int u=b[i].to;
    			if(b[i].val && dis[u]>dis[now]+b[i].cost){
    				dis[u]=dis[now]+b[i].cost;
    				pre[u]=i;
    				incf[u]=std::min(incf[now],b[i].val);
    				if(!inq[u]){
    					inq[u]=1;
    					q.push(u);
    				}
    			}
    		}
    	}
    	return dis[t]!=0x3f3f3f3f;
    }
    int ans1,ans2;
    void updat(){
    	ans1+=incf[t];
    	ans2+=dis[t]*incf[t];
    	rg int now=t,i;
    	while(now){
    		i=pre[now];
    		b[i].val-=incf[t];
    		b[i^1].val+=incf[t];
    		now=b[i^1].to;
    	}
    }
    int main(){
    	memset(h,-1,sizeof(h));
    	n=read(),m=read(),s=read(),t=read();
    	rg int aa,bb,cc,dd;
    	for(rg int i=1;i<=m;i++){
    		aa=read(),bb=read(),cc=read(),dd=read();
    		ad(aa,bb,cc,dd);
    		ad(bb,aa,0,-dd);
    	}
    	while(spfa()) updat();
    	printf("%d %d
    ",ans1,ans2);
    	return 0;
    }
    
    

    代码(dinic)

    #include<cstdio>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<cstring>
    #define rg register
    inline int read(){
    	rg int x=0,fh=1;
    	rg char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    const int maxn=1e5+5;
    int h[maxn],tot=2,s,t,n,m;
    struct asd{
    	int to,nxt,val,cost;
    }b[maxn<<1];
    void ad(rg int aa,rg int bb,rg int cc,rg int dd){
    	b[tot].to=bb;
    	b[tot].nxt=h[aa];
    	b[tot].val=cc;
    	b[tot].cost=dd;
    	h[aa]=tot++;
    }
    int dis[maxn];
    bool inq[maxn];
    std::queue<int> q;
    bool spfa(){
    	memset(dis,0x3f,sizeof(dis));
    	dis[s]=0;
    	q.push(s);
    	inq[s]=1;
    	while(!q.empty()){
    		rg int now=q.front();
    		q.pop();
    		inq[now]=0;
    		for(rg int i=h[now];i!=-1;i=b[i].nxt){
    			rg int u=b[i].to;
    			if(b[i].val && dis[u]>dis[now]+b[i].cost){
    				dis[u]=dis[now]+b[i].cost;
    				if(!inq[u]){
    					inq[u]=1;
    					q.push(u);
    				}
    			}
    		}
    	}
    	return dis[t]!=0x3f3f3f3f;
    }
    int ans1,ans2;
    int dfs(rg int now,rg int ac1){
    	if(now==t){
    		ans1+=ac1;
    		return ac1;
    	}
    	inq[now]=1;
    	rg int ac2=0;
    	for(rg int i=h[now];i!=-1;i=b[i].nxt){
    		rg int u=b[i].to;
    		if(!inq[u] && b[i].val && dis[u]==dis[now]+b[i].cost){
    			rg int nans=dfs(u,std::min(ac1,b[i].val));
    			ac1-=nans,ac2+=nans,b[i].val-=nans,b[i^1].val+=nans;
    			ans2+=nans*b[i].cost;
    		}
    		if(!ac1) break;
    	}
    	inq[now]=0;
    	if(!ac2) dis[now]=0x3f3f3f3f;
    	return ac2;
    }
    int main(){
    	memset(h,-1,sizeof(h));
    	n=read(),m=read(),s=read(),t=read();
    	rg int aa,bb,cc,dd;
    	for(rg int i=1;i<=m;i++){
    		aa=read(),bb=read(),cc=read(),dd=read();
    		ad(aa,bb,cc,dd);
    		ad(bb,aa,0,-dd);
    	}
    	while(spfa()) dfs(s,0x3f3f3f3f);
    	printf("%d %d
    ",ans1,ans2);
    	return 0;
    }
    

    最小/最大费用可行流

    和最小/最大费用最大流的区别是不再需要满足流量最大

    前者有可能为了增广流量而使得总费用变大/变小

    所以要在每次求出最短/最长路之后判断一下 (dis[t]) 是否仍然小于/大于 (0)

    如果不满足就不要继续增广了

  • 相关阅读:
    jquery收集
    c#语法
    asp.net+MVC
    在线OFFICE方案
    NodeJs中require use get typescript及其他知识点集合
    $.data()
    mongodb 安装、windows服务、创建用户
    Nodejs&Express
    Nodejs + MongoDb
    Nodejs
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/14479530.html
Copyright © 2011-2022 走看看