AcWing 287. 积蓄程度,《算法竞赛进阶指南》

287. 积蓄程度 - AcWing题库

有一个树形的水系,由 N−1 条河道和 N 个交叉点组成。

我们可以把交叉点看作树中的节点,编号为 1∼N,河道则看作树中的无向边。

每条河道都有一个容量,连接 x 与 y 的河道的容量记为 c(x,y)。

河道中单位时间流过的水量不能超过河道的容量。

有一个节点是整个水系的发源地,可以源源不断地流出水,我们称之为源点。

除了源点之外,树中所有度数为 11 的节点都是入海口,可以吸收无限多的水,我们称之为汇点。

也就是说,水系中的水从源点出发,沿着每条河道,最终流向各个汇点。

在整个水系稳定时,每条河道中的水都以单位时间固定的水量流向固定的方向。

除源点和汇点之外,其余各点不贮存水,也就是流入该点的河道水量之和等于从该点流出的河道水量之和。

整个水系的流量就定义为源点单位时间发出的水量。

在流量不超过河道容量的前提下,求哪个点作为源点时,整个水系的流量最大,输出这个最大值。

输入格式

输入第一行包含整数 T,表示共有 T 组测试数据。

每组测试数据,第一行包含整数 N。

接下来 N−1行,每行包含三个整数 x,y,z,表示 x,y 之间存在河道,且河道容量为 z�。

节点编号从 1 开始。

输出格式

每组数据输出一个结果,每个结果占一行。

数据保证结果不超过 2^31−1

数据范围

N≤2×105

输入样例:
1
5
1 2 11
1 4 13
3 4 5
4 5 10
输出样例:
26

解析 :二次扫描与换根法

这道题目的标签为树形dp,但我觉得它更像是记忆化搜索

第一次记录仪当前点为根节点的子树的流量

第二次记录仪当前点为根节点的整棵树的流量

最后取最大值


#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long LL;
const int N = 2e5 + 5, M = 2 * N, INF = 0x3f3f3f3f;
int n;
int h[N], e[M], ne[M], w[M], ind;
int deg[N], d[N], f[N], v[N];

void add(int a, int b, int c) {
	e[ind] = b, w[ind] = c, ne[ind] = h[a], h[a] = ind++;
}

void dp(int x) {
	v[x] = 1;
	d[x] = 0;
	for (int i = h[x]; i; i = ne[i]) {
		int y = e[i];
		if (v[y])continue;
		dp(y);
		if (deg[y] == 1)d[x] += w[i];
		else d[x] += min(d[y], w[i]);
	}
}

void dfs(int x) {
	v[x] = 1;
	for (int i = h[x]; i; i = ne[i]) {
		int y = e[i];
		if (v[y])continue;
		if (deg[x] == 1)f[y] = d[y] + w[i];
		else if (deg[y] == 1)
			f[y] = d[y] + min(f[x] - w[i], w[i]);
		else
			f[y] = d[y] + min(f[x] - min(d[y], w[i]), w[i]);
		dfs(y);
	}
}

int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		scanf("%d", &n);
		memset(h, 0, sizeof(h));
		ind = 1;
		memset(deg, 0, sizeof(deg));
		for (int i = 1; i < n; i++) {
			int a, b, c;
			scanf("%d%d%d", &a, &b, &c);
			add(a, b, c), add(b, a, c);
			deg[a]++, deg[b]++;
		}
		int root = 1;
		memset(v, 0, sizeof v);
		dp(root);
		memset(v, 0, sizeof v);
		f[root] = d[root];
		dfs(root);
		int ans = 0;
		for (int i = 1; i <= n; i++)ans = max(ans, f[i]);
		cout << ans << endl;
	}
	return 0;
}

posted @ 2023-10-04 15:38  Landnig_on_Mars  阅读(18)  评论(0编辑  收藏  举报  来源