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\n", g.MaxFlow, g.MinCost);
	return 0;
}

  

posted @ 2018-03-28 22:49  headboy2002  阅读(108)  评论(0编辑  收藏  举报