zoukankan      html  css  js  c++  java
  • 最小费用最大流模板

    最小费用最大流模板

    给出一个容量网络,那他的最大流一定是一个定值(即使是有多个一样的最大值)。所以我们从开始的可行流开始增广时,最终的增广量是一定的。所以为了满足最小费用我们只需要每次找最小费用的增广路即可,直到流量为最大值。这个问题仅仅是在求增广路时先考虑费用最小的增广路,其他思想和EK思想一样。
    我们学过SPFA求最短路算法(bellman-ford的队列优化),所以我们将弧的费用看做是路径长度,即可转化为求最短路的问题了。只需要所走的最短路满足两个条件即可:1可增广cap> flow,2路径变短d[v]>d[u]+cost< u,v>

    网络流(六)最小费用最大流问题

    其实就是把dinic中的bfs换成spfa,dfs换成回溯修改剩余网络和答案的过程。

    算法流程:

    1. 用spfa寻找每条边上费用之和最小的增广路,沿途找到最小流量,把经过的点记录下来。
    2. 把最小费用增广路上的边剩余流量修改了
    3. 回到1

    注意,反边费用为其对应边的相反数

    ps:有个很神奇的地方没搞懂:一开始我忘记打spfa里面“bz[x]=0;”这一句,结果算出的最大流比答案大?!!

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    struct qy
    {
    	int x,y,flow,cost;
    };
    
    int n,m,S,T,i,j,x,y,z1,z2,tot,maxflow,mincost;
    qy l[200005];
    int next[200005],last[200005];
    int dis[5005],flow[5005],from[5005],bz[5005];
    int list[200005],head,tail;
    
    void insert(int x,int y,int z1,int z2)
    {
    	tot++;
    	l[tot].x=x;
    	l[tot].y=y;
    	l[tot].flow=z1;
    	l[tot].cost=z2;
    	next[tot]=last[x];
    	last[x]=tot;
    }
    
    int spfa()
    {
    	memset(bz,0,sizeof(bz));
    	memset(flow,0,sizeof(flow));
    	memset(dis,120,sizeof(dis));
    	list[1]=S;bz[S]=1;head=0;tail=1;dis[S]=0;flow[S]=1000000000;
    	while (head<tail)
    	{
    		int x=list[++head];
    		for (int i=last[x];i>=1;i=next[i])
    		{
    			int y=l[i].y;
    			if ((l[i].flow>0)&&(dis[y]>dis[x]+l[i].cost))
    			{
    				dis[y]=dis[x]+l[i].cost;
    				from[y]=i;
    				flow[y]=min(flow[x],l[i].flow);
    				if (!bz[y])
    				{
    					bz[y]=1;list[++tail]=y;
    				}
    			}
    		}
    		bz[x]=0;
    	}
    	if (flow[T]>0) return 1;
    	else return 0;
    }
    
    void mfmc()
    {
    	while (spfa())
    	{
    		maxflow+=flow[T];
    		mincost+=flow[T]*dis[T];
    		for (int x=T;x!=S;x=l[from[x]].x)
    		{
    			l[from[x]].flow-=flow[T];
    			l[from[x]^1].flow+=flow[T];
    		}
    	}
    }
    
    int main()
    {
    	freopen("read.in","r",stdin);
    	scanf("%d%d%d%d",&n,&m,&S,&T);
    	tot=1;
    	for (i=1;i<=m;i++)
    	{
    		scanf("%d%d%d%d",&x,&y,&z1,&z2);
    		insert(x,y,z1,z2);
    		insert(y,x,0,-z2);
    	}
    	mfmc();
    	printf("%d %d",maxflow,mincost);
    }
    
  • 相关阅读:
    C#中KeyDown和KeyPress区别
    c#快捷键设置和text输入限制
    问题总结
    c#串口编程和单片机通信重大发现
    c#类似单片机的8bit或运算
    c#中将默认常量(32bit)转换为8bit
    我的秋季个人阅读计划
    学期总结
    阅读笔记《软件秘籍》03
    阅读笔记--09
  • 原文地址:https://www.cnblogs.com/leason-lyx/p/11147261.html
Copyright © 2011-2022 走看看