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

    题目描述

    如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用。

    输入输出格式

    输入格式:

    第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个数、源点序号、汇点序号。

    接下来M行每行包含四个正整数ui、vi、wi、fi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi),单位流量的费用为fi。

    输出格式:

    一行,包含两个整数,依次为最大流量和在最大流量情况下的最小费用。

    输入输出样例

    输入样例#1:
    4 5 4 3
    4 2 30 2
    4 3 20 3
    2 3 20 1
    2 1 30 9
    1 3 40 5
    输出样例#1:
    50 280

    说明

    时空限制:1000ms,128M

    (BYX:最后两个点改成了1200ms)

    数据规模:

    对于30%的数据:N<=10,M<=10

    对于70%的数据:N<=1000,M<=1000

    对于100%的数据:N<=5000,M<=50000

    样例说明:

    如图,最优方案如下:

    第一条流为4-->3,流量为20,费用为3*20=60。

    第二条流为4-->2-->3,流量为20,费用为(2+1)*20=60。

    第三条流为4-->2-->1-->3,流量为10,费用为(2+9+5)*10=160。

    故最大流量为50,在此状况下最小费用为60+60+160=280。

    故输出50 280。

    /*
    	最小费用最大流:
    	
    	对于一个网络,它的最大流是唯一的,最大流一定是一个定值(即使是有多个一样的最大值),而
    	在最大流一定的情况下费用却不一定是一定的,最小费用最大流就是在最大流一定的情况下求解最
    	小费用。所以为了满足最小费用我们只需要每次找小费用的增广路即可,直到流量为最大值。所以
    	最只需在求增广路时先考虑费用最小的增广路。将弧的费用看做是路径长度,即可转化为求最短路
    	的问题了。只需要所走的最短路满足两个条件即可:1可增广cap> flow,2路径变短d[v]>d[u]+cost< u,v>
    	
    */
    
     #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<queue>
    
    using namespace std;
    const int N=1e4+10;//dian
    const int NN=1e5+10;//bian
    const int INF=9999999;
    
    int head[N],now=1,W[N],pre[N];
    int n,m,S,T,nflow,flow,fee;
    int _u,_v,_river,_mon;
    bool vis[N];
    struct node{
    	int u,v,river,mon,nxt;
    }E[NN];
    queue<int>Q;
    
    inline int read()
    {
    	int x=0;char c=getchar();
    	while(c<'0'||c>'9')c=getchar();
    	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
    	return x;
    }
    
    inline void add(int _u,int _v,int _river,int _mon)
    {
    	E[now].u=_u;
    	E[now].v=_v;
    	E[now].river=_river;
    	E[now].mon=_mon;
    	E[now].nxt=head[_u];
    	head[_u]=now++;
    }
    
    int AP(int k,int v)
    {
    	if(k==S)return v;
    	int ret=AP(E[pre[k]].u,min(v,E[pre[k]].river));
    	if(!E[pre[k]^1].mon)
    	{
    		now=pre[k]^1;
    		add(k,E[pre[k]].u,0,-E[pre[k]].mon);
    	}
    	E[pre[k]].river-=ret;
    	E[pre[k]^1].river+=ret;
    	return ret;
    }
    
    inline void MCMF()
    {
    	while(1)
    	{
    		for(int i=1;i<=n;i++)
    			W[i]=INF,vis[i]=0;
    		W[S]=0;vis[S]=1;
    		Q.push(S);
    		while(!Q.empty())
    		{
    			int topp=Q.front();
    			Q.pop();
    			vis[topp]=0;
    			for(int i=head[topp];~i;i=E[i].nxt)
    				if(W[E[i].v]>E[i].mon+W[topp]&&E[i].river)
    				{
    					pre[E[i].v]=i;
    					W[E[i].v]=E[i].mon+W[topp];
    					if(!vis[E[i].v])
    						vis[E[i].v]=1,
    						Q.push(E[i].v);
    				}
    		}
    		if(W[T]==INF)
    			break;
    		nflow=AP(T,INF);
    		flow+=nflow;
    		fee+=nflow*W[T];
    	}
    }
    
    int main()
    {
    	n=read(),m=read(),S=read(),T=read();
    	for(int i=1;i<=n;i++)
    		head[i]=-1;
    	for(int i=1;i<=m;i++)
    	{
    		_u=read(),_v=read(),_river=read(),_mon=read();
    		++now;//给 该边^1 后的边留出位置 
    		add(_u,_v,_river,_mon);
    	}
    	MCMF();
    	printf("%d %d
    ",flow,fee);
    	return 0;
    }
    
    /*
    4 5 4 3
    4 2 30 2
    4 3 20 3
    2 3 20 1
    2 1 30 9
    1 3 40 5
    */
    

      

      

  • 相关阅读:
    git常用命令
    vue+el-menu+vue-router实现动态导航条
    css实现文字内容超出显示省略号
    背景图片居中全屏自适应显示
    linux相关操作(虚拟环境、查看进程)(不定时更新)
    关于定义序列化器时,read_only和write_only有什么作用
    flask之请求与响应、闪现(阅后即焚)、请求扩展(before,after)、中间件、LOCAL对象、偏函数、
    flask之web网关、三件套、配置、路由(参数、转化器及自定义转化器)、cbv、模板语言、session
    flask中的endpoint、自定义转化器、与djnago中session区别、利用装饰器实现登录认证
    jinja2模板用法
  • 原文地址:https://www.cnblogs.com/lyqlyq/p/7209887.html
Copyright © 2011-2022 走看看