• 图论:网络流最小费用最大流


    P3381 【模板】最小费用最大流

    添加了弧优化

    点击查看折叠代码块
    /*
    最大流最小费用
    费用为单位流量的费用
    在最大流的前提下找最短路径即为最小费用
    边权为当前边的流量乘以单位流量的费用
    
    首先构建一个图用最短路算法来找到源点到各个点的最短距离
    找到这个数据之后,我们就可以沿着最短路来进行增广,
    即在最短路中求到一条可行路然后修改其残量,我们可以保证其为最大流中的一部分的最小花费
    不断的进行增广直到我们找到了全部值,然后得解,
    这就是将dinic和spfa结合起来的求解最小费用最大流问题的方法
    
    spfa使用small label first 优化,用deque实现 
    
    若要求最大费用
    将单位费用改为-w,最终答案取相反数即为最大费用
    */
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxm=1e6+10;
    const int maxn=5e3+10;
    const ll inf = (1ll<<62);
    struct edge{
    	int v,next;
    	ll c,w;//边最大流量,单位流量的费用 
    }e[maxm<<1];
    
    int head[maxn],cnt=0;
    int n,m,s,t;
    
    void add(int u,int v,ll c,ll w){
        e[cnt].v=v;e[cnt].c=c;e[cnt].w=w;e[cnt].next=head[u];head[u]=cnt++;
        e[cnt].v=u;e[cnt].c=0;e[cnt].w=-w;e[cnt].next=head[v];head[v]=cnt++;
    }
    
    void init(){
    	memset(head,-1,sizeof(head));
    	cnt=0;
    }
    int tot;
    ll mincost = 0,maxflow = 0;
    int cur[maxn];//当前弧优化
    ll dis[maxn];
    bool vis[maxn];
    bool spfa(int s,int t){
    	for (int i=0;i<=tot;i++) dis[i] = inf,vis[i] = 0;//这里需要注意初始化应该要初始化到最大上界tot
    	dis[s] = 0;
    	vis[s] = 1;
    	deque<int> dq;
    	dq.push_front(s);
    	
    	while(!dq.empty()){
    		int u=dq.front();
    		dq.pop_front();
    		vis[u] = 0;
    		for (int i=head[u];~i;i=e[i].next){
    			int v=e[i].v;
    			ll c=e[i].c;//边的流量 
    			ll w=e[i].w;//单位流量的花费——边的权值 
    			if(c>0 && dis[v] > dis[u] + w){//当前有残量并且是最短路上的边 
    				dis[v]=dis[u]+w;//更新最短路
    				if(!vis[v]){
    					vis[v]=1;
    					if(!dq.empty() && dis[dq.front()]>dis[v]){//SLF优化,如果v的dis比队列的头dis较小,放入队首
    						dq.push_front(v);
    					}
    					else dq.push_back(v);
    				}
    			}
    		}
    	}
    	return dis[t]!=inf;
    }
    
    ll dfs(int u,int t,ll flow){//在最短路的基础上在残量网络中找增广路 
    	if(u == t) return flow;
    	ll delta = flow;
    	vis[u] = true;
    	for (int i=cur[u];~i;i=e[i].next){
    		cur[u]=i;
    		int v=e[i].v;
                    ll w=e[i].w,c=e[i].c;
    		if(c>0 && !vis[v] && dis[v] == dis[u] + w){//注意vis的初始化,spfa和dfs中都用到了 
    			ll d=dfs(v,t,min(c,delta));
                            if(!d) dis[v] = 0;
    			e[i].c-=d;
    			e[i^1].c+=d;
    			delta-=d;
    			mincost+=w*d;
    			if(delta == 0) break;
    		}
    	}
    	vis[u] = false;
    	return flow-delta;
    }
    
    void min_cost_max_flow(int s,int t){
    	while(spfa(s,t)){
    		memset(vis,0,sizeof(vis));
                    memcpy(cur,head,sizeof(cur));
    		maxflow+=dfs(s,t,inf);
    	}
    }
    
    int main(){
        init();
        cin>>n>>m>>s>>t;
        tot = n;
        for (int i=1;i<=m;i++){
            int u,v;ll w,c;
            scanf("%d%d%lld%lld",&u,&v,&c,&w);//将单位费用改为-w,最终答案取相反数即为最大费用
            add(u,v,c,w);
        }
        min_cost_max_flow(s,t);
        printf("%lld %lld
    ",maxflow,mincost);
        return 0;
    }
    
    你将不再是道具,而是成为人如其名的人
  • 相关阅读:
    快速读取txt文档
    ASP.NET中缓存非SQLServer数据库数据
    查看linq to sql 生成的sql 语句
    跟树有关的数据结构学习系列之概览
    Linux安装软件包时的“依赖关系树”算法(C#)
    Go调度器介绍和容易忽视的问题
    搞懂Go垃圾回收
    Go“一个包含nil指针的接口不是nil接口”踩坑
    Go slice:切片的“陷阱”和本质
    C#调用ODBC连接SQL Server数据库的存储过程
  • 原文地址:https://www.cnblogs.com/wsl-lld/p/13393592.html
Copyright © 2020-2023  润新知