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;
    }
    

      

  • 相关阅读:
    iphone, iphone4, ipad 图标和背景图片问题(转)
    ios项目icon和default图片命名规则 (转)
    ios判断设备是iphone还是ipad
    cocos2d学习(一)helloWorld
    判断设备是否是 iphone5
    字节对齐(转)
    NSArray排序
    C++复习之运算符重载,数组排序,vector
    socket编程(转)
    win32下的socket编程
  • 原文地址:https://www.cnblogs.com/headboy2002/p/8666941.html
Copyright © 2011-2022 走看看