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

    最小费用最大流,我们再次用管道水流比喻。现在,每个管道对于1横截面积的水流有个费用。现要求最大流的水流方案中花费最小的那一个。

    不断用SPFA找到从源点到汇点的最短可增广路径,并将尽可能多的水流注入该可增广路径即可。注意一段增广路径的最大流量为其组成的边中剩余容量最小的边的剩余容量。

    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <algorithm>
    using namespace std;
    
    const int MAX_NODE = 5010, MAX_EDGE = 50010 * 2, INF = 0x3f3f3f3f;
    #define LOOP(i, n) for(int i=1; i<=n; i++)
    
    struct MCMF
    {
    private:
    	struct Node;
    	struct Edge;
    
    	struct Node
    	{
    		Edge *Head, *Prev;
    		int Id, Dist;
    		bool Inq;
    	}_nodes[MAX_NODE], *Start, *Target;
    	int _vCount;
    
    	struct Edge
    	{
    		Node *From, *To;
    		Edge *Next, *Rev;
    		int Cap, Cost;
    	}*_edges[MAX_EDGE];
    	int _eCount;
    
    	Edge *NewEdge()
    	{
    		return _edges[++_eCount] = new Edge();
    	}
    
    	Edge *AddEdge(Node *from, Node *to, int cap, int cost)
    	{
    		Edge *e = NewEdge();
    		e->From = from;
    		e->To = to;
    		e->Cap = cap;
    		e->Cost = cost;
    		e->Next = e->From->Head;
    		e->From->Head = e;
    		return e;
    	}
    
    	bool SPFA()
    	{
    		static queue<Node*> q;
    		LOOP(i, _vCount)
    		{
    			_nodes[i].Prev = NULL;//易忘点
    			_nodes[i].Dist = INF;
    			_nodes[i].Inq = false;
    		}
    		Start->Dist = 0;
    		Start->Inq = true;
    		q.push(Start);
    		while (!q.empty())
    		{
    			Node *cur = q.front();
    			q.pop();
    			cur->Inq = false;
    			for (Edge *e = cur->Head; e; e = e->Next)
    			{
    				if (e->Cap && cur->Dist + e->Cost < e->To->Dist)
    				{
    					e->To->Dist = cur->Dist + e->Cost;
    					e->To->Prev = e;
    					if (!e->To->Inq)
    					{
    						e->To->Inq = true;
    						q.push(e->To);
    					}
    				}
    			}
    		}
    		return Target->Prev;
    	}
    
    public:
    	int MinCost, MaxFlow;
    
    	void Init(int totNode, int sId, int tId)
    	{
    		_vCount = totNode;
    		memset(_nodes, 0, sizeof(_nodes));
    		memset(_edges, 0, sizeof(_edges));
    		_eCount = 0;
    		Start = _nodes + sId;
    		Target = _nodes + tId;
    	}
    
    	void Build(int uId, int vId, int cap, int cost)
    	{
    		Node *u = _nodes + uId, *v = _nodes + vId;
    		u->Id = uId;
    		v->Id = vId;
    		Edge *e1 = AddEdge(u, v, cap, cost), *e2 = AddEdge(v, u, 0, -cost);
    		e1->Rev = e2;
    		e2->Rev = e1;
    	}
    
    	void Proceed()
    	{
    		MinCost = MaxFlow = 0;
    		while (SPFA())
    		{
    			int flow = INF;
    			for (Edge *e = Target->Prev; e; e = e->From->Prev)
    				flow = min(flow, e->Cap);
    			MaxFlow += flow;
    			for (Edge *e = Target->Prev; e; e = e->From->Prev)
    			{
    				e->Cap -= flow;
    				e->Rev->Cap += flow;
    				MinCost += e->Cost * flow;
    			}
    		}
    	}
    }g;
    
    int main()
    {
    	int n, m, sId, tId, uId, vId, cap, cost;
    	scanf("%d%d%d%d", &n, &m, &sId, &tId);
    	g.Init(n, sId, tId);
    	while (m--)
    	{
    		scanf("%d%d%d%d", &uId, &vId, &cap, &cost);
    		g.Build(uId, vId, cap, cost);
    	}
    	g.Proceed();
    	printf("%d %d
    ", g.MaxFlow, g.MinCost);
    	return 0;
    }
    

      

  • 相关阅读:
    oracle之数据限定与排序
    oracle之分组函数
    oracle之SQL的数据类型
    lftp简单使用
    黑盘-蓝盘-绿盘-红盘
    windows 路由
    http扩展请求头中的x-Forwarded-For
    http状态码304
    firewall 实现数据的端口转发
    通过curl获取网页访问时间
  • 原文地址:https://www.cnblogs.com/headboy2002/p/8666941.html
Copyright © 2011-2022 走看看