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

      

  • 相关阅读:
    Python 文件Hash(MD5,SHA1)
    CDHtmlDialog探索Javascript与窗体交互
    C++ 实现不允许继承的类
    (一)JDBC入门及简介
    (二)JDBC 连接数据库
    2012年,总结
    canvas 时钟
    解决数据库日志文件过满的又一方法
    Windows XP 注册表修改大全
    windows2003中安装.netframework1.1
  • 原文地址:https://www.cnblogs.com/headboy2002/p/8666941.html
Copyright © 2020-2023  润新知