• 费用流入门


    与最大流不同之处在于,每条弧不只有流量,还添加了费用

    流过每条边的费用为这条边的流量×费用

    一般问题是最小费用最大流,即在最大流的前提下要求总费用最小

    众所周知:(spfa) 它还能续一命

    (dij)是处理不了负边权的,当然如果您是(NOI2018)现场爷并且有某些心里阴影的话,那您应该不会看我的博客学费用流啊

    网上有些题解说是(dinic)算法魔改一下,把(BFS)改成(spfa)就好了,但是其实还是有点区别的吧

    的确费用流和(dinic)都是多路增广但是由于费用流要兼顾最小费用的原则,每次增广的优先条件是费用最小,而非流量最大

    当然这也是在有增广路的前提下,也就是说每次增广流量必定在增大

    所以费用流的复杂度更加选学,它并不是多项式级别的,理论上界应该是(O(nmc)),其中(c)是最大流的流量

    对反向边我们需要增加一些操作:将反向边费用设为负的,这样才能满足流过反向边完全抵消正向边的影响

    代码是以前写的,格式和现在有所不同,不过还算规范

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    inline int read()
    {
    	int x=0,f=1;
    	char ch;
    	for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    	if(ch=='-') f=0,ch=getchar();
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    	return f?x:-x;
    }
    const int inf=0x3f3f3f3f3f3f3f3f;
    int n,m,st,ed;
    int maxf,minv;
    int c[10010],dis[10010];
    bool vis[10010];
    int pre[10010],eg[10010];
    int head[10010],cnt=1;
    struct point
    {
    	int nxt,to,val,c;
    }a[100010];
    inline void add(int x,int y,int v,int f)
    {
    	a[++cnt].nxt=head[x];
    	a[cnt].to=y;;
    	a[cnt].val=v;
    	a[cnt].c=f;
    	head[x]=cnt;
    }
    queue<int> q;
    inline bool spfa()
    {
    	memset(c,0x3f,sizeof(c));
    	memset(dis,0x3f,sizeof(dis));dis[st]=0;
    	memset(vis,0,sizeof(vis));vis[st]=1;
    	q.push(st);pre[ed]=0;
    	while(!q.empty())
    	{
    		int now=q.front();
    		q.pop();
    		vis[now]=0;
    		for(int i=head[now];i;i=a[i].nxt)
    		{
    			int t=a[i].to;
    			if(a[i].c&&dis[t]>dis[now]+a[i].val)
    			{
    				pre[t]=now;
    				eg[t]=i;
    				dis[t]=dis[now]+a[i].val;
    				c[t]=min(c[now],a[i].c);
    				if(!vis[t])
    				{
    					vis[t]=1;
    					q.push(t);
    				}
    			}
    		}
    	}
    	return pre[ed];
    }
    inline void dinic()
    {
    	while(spfa())
    	{
    		int now=ed;
    		maxf+=c[ed];
    		minv+=c[ed]*dis[ed];
    		while(now!=st)
    		{
    			a[eg[now]].c-=c[ed];
    			a[eg[now]^1].c+=c[ed];
    			now=pre[now];
    		}
    	}
    }
    signed main()
    {
    	n=read(),m=read(),st=read(),ed=read();
    	for(int x,y,z,v,i=1;i<=m;++i)
    	{
    		x=read(),y=read(),z=read(),v=read();
    		add(x,y,v,z);
    		add(y,x,-v,0);
    	}
    	dinic();
    	printf("%lld %lld
    ",maxf,minv);
    return 0;
    }
    

    费用流一般用法是构造最大流然后求最小费用

  • 相关阅读:
    http从发出请求到接收响应的旅行
    git(二)github的使用入门及搜索技巧
    git(一) 基础
    获取基于Internet Explorer_Server的聊天窗口内容
    主机字节与网络字节的转换
    SQL Server存储过程中防止线程重入处理方式
    利用NVelocity 模版生成文本文件
    C# async await 学习笔记2
    C# async await 学习笔记1
    imx6 工具链下载地址
  • 原文地址:https://www.cnblogs.com/knife-rose/p/12094781.html
Copyright © 2020-2023  润新知