zoukankan      html  css  js  c++  java
  • 【CF708D】Incorrect Flow 最小费用可行流

    【CF708D】Incorrect Flow

    题意:给你一个点数为n,边数为m的流网络,每条边有一个容量c和流量f,这个网络可能是不合法的。你可以花费1的代价使c或f减少或增加1,可以修改无限次。你不需要使流量最大,你只需要花费最少的代价把原图改造成一个合法的网络。

    $n,mle 100,c,fle 10^6$

    题解:我们用有上下界的费用流来解决这个问题。

    对于一条边a->b,如果c>f,则我们从a到b连一条下界和上界都是f,费用为0的边;因为可以减少流量,所以连一条从b到a,容量为f,费用为1的边;因为可以增加流量,所以连一条从a到b,容量为c-f,费用为1的边;因为可以同时增加容量和流量,所以连一条从a到b,容量为inf,费用为2的边。

    如果c<f,则我们先补充f-c个容量,直接将其加到答案中去,然后连一条从a到b,下界和上界都是f,费用为0的边;因为可以同时增加流量和容量,所以连一条从a到b,容量为inf,费用为2的边;因为可以减少流量,当减少量<f-c时,我们可以撤销一开始增加容量的操作,所以连一条从b到a,容量为f-c,费用为0的边;当减少量>f-c时,我们连一条从b到a,容量为c,费用为1的边。

    跑最小费用可行流即可。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    
    using namespace std;
    int n,m,cnt,ans,S,T;
    int to[100010],nxt[100010],head[210],cost[100010],flow[100010],dis[210],pe[210],pv[210],inq[210],ml[210];
    queue<int> q;
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
    	return ret*f;
    }
    int bfs()
    {
    	int i,u;
    	memset(dis,0x3f,sizeof(dis));
    	q.push(S),dis[S]=0;
    	while(!q.empty())
    	{
    		u=q.front(),q.pop(),inq[u]=0;
    		for(i=head[u];i!=-1;i=nxt[i])	if(flow[i]&&dis[to[i]]>dis[u]+cost[i])
    		{
    			dis[to[i]]=dis[u]+cost[i],pe[to[i]]=i,pv[to[i]]=u;
    			if(!inq[to[i]])	q.push(to[i]),inq[to[i]]=1;
    		}
    	}
    	return dis[T]<0x3f3f3f3f;
    }
    inline void add(int a,int b,int c,int d)
    {
    	to[cnt]=b,cost[cnt]=c,flow[cnt]=d,nxt[cnt]=head[a],head[a]=cnt++;
    	to[cnt]=a,cost[cnt]=-c,flow[cnt]=0,nxt[cnt]=head[b],head[b]=cnt++;
    }
    int main()
    {
    	n=rd(),m=rd();
    	int i,a,b,c,f;
    	S=0,T=n+1;
    	memset(head,-1,sizeof(head));
    	for(i=1;i<=m;i++)
    	{
    		a=rd(),b=rd(),c=rd(),f=rd();
    		if(c<f)
    		{
    			ans+=f-c;
    			ml[a]+=f,ml[b]-=f;
    			add(b,a,0,f-c),add(b,a,1,c),add(a,b,2,1<<30);
    		}
    		else
    		{
    			ml[a]+=f,ml[b]-=f;
    			add(a,b,1,c-f),add(a,b,2,1<<30),add(b,a,1,f);
    		}
    	}
    	add(n,1,0,1<<30);
    	for(i=1;i<=n;i++)
    	{
    		if(ml[i]>=0)	add(i,T,0,ml[i]);
    		else	add(S,i,0,-ml[i]);
    	}
    	while(bfs())
    	{
    		f=1<<30;
    		for(i=T;i!=S;i=pv[i])	f=min(f,flow[pe[i]]);
    		ans+=dis[T]*f;
    		for(i=T;i!=S;i=pv[i])	flow[pe[i]]-=f,flow[pe[i]^1]+=f;
    	}
    	printf("%d",ans);
    	return 0;
    }
  • 相关阅读:
    PyQt5复杂控件(树控件、选项卡控件(滚动条控件、多文档控件、停靠控件)
    PyQt5单元格操作大全
    PyQt5打印机
    PyQt5剪切板操作
    PyQt5的菜单栏、工具栏和状态栏
    PyQt5日历控件及相关操作
    PyQt5控件支持拖拽方法
    《Lua程序设计》第3章 表达式 学习笔记
    Lua中的table构造式(table constructor)
    《Lua程序设计》第2章 类型与值 学习笔记
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8503998.html
Copyright © 2011-2022 走看看