1. 程式人生 > >洛谷 P4722 最大流最快模板

洛谷 P4722 最大流最快模板

題意:直接給出網路流建圖資訊,求最大流

 

一般的dinic演算法和isap演算法複雜度為O(n^2m),此題有專門資料會卡這兩個演算法。

因此一種複雜度上界在常用最大流演算法中最優的最高標號預留推進演算法(又叫HLPPHLPP),其上界為O(n^2 \sqrt m),並且在經過優化後這種演算法在資料隨機的情況下速度也不亞於上述兩種增廣路演算法

不會,直接上板子以後用。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using std::min;
using std::vector;
using std::queue;
using std::priority_queue;
const int N = 2e4 + 5;
const int M = 2e5 + 5;
const int inf = 0x3f3f3f3f;
int n, s, t, tot;
int v[M << 1], w[M << 1], first[N], next[M << 1];
int h[N], e[N], gap[N << 1], inq[N];
struct cmp
{
	inline bool operator()(int a, int b) const
	{
		return h[a]<h[b];
	}
};
queue<int> Q;
priority_queue<int, vector<int>, cmp> pQ;
inline void add_edge(int from, int to, int flow)
{
	tot += 2;
	v[tot + 1] = from;v[tot] = to;w[tot] = flow;w[tot + 1] = 0;
	next[tot] = first[from];first[from] = tot;
	next[tot + 1] = first[to];first[to] = tot + 1;
	return;
}
inline bool bfs()
{
	int now;
	register int go;
	memset(h + 1, 0x3f, sizeof(int)*n);
	h[t] = 0;Q.push(t);
	while (!Q.empty())
	{
		now = Q.front();Q.pop();
		for (go = first[now];go;go = next[go])
			if (w[go ^ 1] && h[v[go]]>h[now] + 1)
				h[v[go]] = h[now] + 1, Q.push(v[go]);
	}
	return h[s] != inf;
}
inline void push(int now)
{
	int d;
	register int go;
	for (go = first[now];go;go = next[go])
		if (w[go] && h[v[go]] + 1 == h[now])
		{
			d = min(e[now], w[go]);
			w[go] -= d;w[go ^ 1] += d;e[now] -= d;e[v[go]] += d;
			if (v[go] != s&&v[go] != t && !inq[v[go]])
				pQ.push(v[go]), inq[v[go]] = 1;
			if (!e[now])
				break;
		}
	return;
}
inline void relabel(int now)
{
	register int go;
	h[now] = inf;
	for (go = first[now];go;go = next[go])
		if (w[go] && h[v[go]] + 1<h[now])
			h[now] = h[v[go]] + 1;
	return;
}
inline int hlpp()
{
	int now, d;
	register int i, go;
	if (!bfs())
		return 0;
	h[s] = n;
	memset(gap, 0, sizeof(int)*(n << 1));
	for (i = 1;i <= n;i++)
		if (h[i]<inf)
			++gap[h[i]];
	for (go = first[s];go;go = next[go])
		if (d = w[go])
		{
			w[go] -= d;w[go ^ 1] += d;e[s] -= d;e[v[go]] += d;
			if (v[go] != s&&v[go] != t && !inq[v[go]])
				pQ.push(v[go]), inq[v[go]] = 1;
		}
	while (!pQ.empty())
	{
		inq[now = pQ.top()] = 0;pQ.pop();push(now);
		if (e[now])
		{
			if (!--gap[h[now]])
				for (i = 1;i <= n;i++)
					if (i != s&&i != t&&h[i]>h[now] && h[i]<n + 1)
						h[i] = n + 1;
			relabel(now);++gap[h[now]];
			pQ.push(now);inq[now] = 1;
		}
	}
	return e[t];
}
int m;
signed main()
{
	int u, v, w;
	scanf("%d%d%d%d", &n, &m, &s, &t);
	while (m--)
	{
		scanf("%d%d%d", &u, &v, &w);
		add_edge(u, v, w);
	}
	printf("%d\n", hlpp());
	return 0;
}