HDU 1532 Drainage Ditches【HLPP网络流(最高标号预流推进)】

HDU 1532 Drainage Ditches

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<string>
#include<map>
#include<queue>
#include<vector>
using namespace std;
const int maxe = 2e6 + 10;
const int maxn = 1e3 + 10;
const int INF = 0x3f3f3f3f;
struct edge {
	int to, nx, w;
}e[maxe];
int head[maxn];
int sz, n, m;
int prs[maxn], gap[maxn], d[maxn];
//bool able[maxn];
//vector<int> inv[maxn];
void add(int u, int v, int w) {
	e[sz].to = v;//建立正边
	e[sz].w = w;
	e[sz].nx = head[u];
	head[u] = sz++;
	e[sz].to = u;//建立反边
	e[sz].w = 0;
	e[sz].nx = head[v];
	head[v] = sz++;
}
struct cmp {//建立一个,按照h为顺序的大顶堆。
	int x, h;
	cmp(int x = 0, int h = 0) :x(x), h(h) {}
	inline bool operator < (const cmp &a) const { return h < a.h; }//运算符重载
};
priority_queue<cmp> pq;
bool push(int x, int y, int p) {// u, v, id;
	int w = min(prs[x], e[p].w);// 尽可能满流
	e[p].w -= w; e[p ^ 1].w += w; prs[x] -= w; prs[y] += w;
	return w;
}
void Gap(int l, int s, int t) {//如果某点的位置抬高1之后,这个点原来的高度就已经不存在点了
	//那么我们直接把大于这个高度的点全部设置为高度(n+1),让他们直接回流到S
	for (int i = 1; i <= n; i++) {
		if (i != s && i != t && l < d[i] && d[i] <= n) d[i] = n + 1;
	}
}
int maxflow(int s, int t) {
	while (!pq.empty()) pq.pop();
	memset(prs, 0, sizeof prs);
	memset(d, 0, sizeof d);
	memset(gap, 0, sizeof gap);
	d[s] = n; prs[s] = INF; pq.push(cmp(s, d[s]));
	while (!pq.empty()) {
		int x = pq.top().x;
		pq.pop();
		if (!prs[x]) continue;//没有余流
		for (int i = head[x]; i != -1; i = e[i].nx) {
			int v = e[i].to; int w = e[i].w;
			if ((x == s || d[x] == d[v] + 1) && push(x, v, i) && v != t && v != s) {
				pq.push(cmp(v, d[v]));
			}
		}
		if (x != s && x != t && prs[x]) {//有余流,需要抬高一层,如果在s就没必要往上抬了(抬不动了QAQ)
			if (!(--gap[d[x]])) Gap(d[x], s, t);//如果低一层没有元素,发生断档,直接Gap回流给S
			++gap[++d[x]];//抬高一层
			pq.push(cmp(x, d[x]));
		}
	}
	return prs[t];//返回T流量
}
int main() {
	while (~scanf("%d %d", &m, &n)) {
		memset(head, -1, sizeof head); sz = 0;
		for (int i = 1; i <= m; i++) {
			int u, v, w;
			scanf("%d %d %d", &u, &v, &w);
			if (w == 0) continue;//无效边
			add(u, v, w);
		}
		int ans = maxflow(1, n);
		printf("%d\n", ans);
	}
	return 0;
}
//_CRT_SECURE_NO_WARNINGS


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值