
[l洛谷 P2986 USACO10MAR] 奶牛农场
Bessie 正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会。当然,她会选择最方便的地点来举办这次集会。每个奶牛居住在N个农场中的一个,这些农场由N−1条道路连接,并且从任意一个农场都能够到达另外一个农场。道路i连接农场Ai和Bi,长度为Li。集会可以在N个农场中的任意一个举行。另外,每个牛棚中居住着Ci只奶牛。在选择集会的地点的时候,Bessie 希望最大化方便的程度
P2986 [USACO10MAR] Great Cow Gathering G
题目描述
Bessie 正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会。当然,她会选择最方便的地点来举办这次集会。
每个奶牛居住在 N N N 个农场中的一个,这些农场由 N − 1 N-1 N−1 条道路连接,并且从任意一个农场都能够到达另外一个农场。道路 i i i 连接农场 A i A_i Ai 和 B i B_i Bi,长度为 L i L_i Li。集会可以在 N N N 个农场中的任意一个举行。另外,每个牛棚中居住着 C i C_i Ci 只奶牛。
在选择集会的地点的时候,Bessie 希望最大化方便的程度(也就是最小化不方便程度)。比如选择第 X X X 个农场作为集会地点,它的不方便程度是其它牛棚中每只奶牛去参加集会所走的路程之和(比如,农场 i i i 到达农场 X X X 的距离是 20 20 20,那么总路程就是 C i × 20 C_i\times 20 Ci×20)。帮助 Bessie 找出最方便的地点来举行大集会。
输入格式
第一行一个整数 N N N 。
第二到 N + 1 N+1 N+1 行:第 i + 1 i+1 i+1 行有一个整数 C i C_i Ci。
第 N + 2 N+2 N+2 行到 2 N 2N 2N 行:第 i + N + 1 i+N+1 i+N+1 行为 3 3 3 个整数: A i , B i A_i,B_i Ai,Bi 和 L i L_i Li。
输出格式
一行一个整数,表示最小的不方便值。
输入输出样例 #1
输入 #1
5
1
1
0
0
2
1 3 1
2 3 2
3 4 3
4 5 3
输出 #1
15
说明/提示
1
≤
N
≤
1
0
5
1\leq N\leq 10^5
1≤N≤105,
1
≤
A
i
≤
B
i
≤
N
1\leq A_i\leq B_i\leq N
1≤Ai≤Bi≤N,
0
≤
C
i
,
L
i
≤
1
0
3
0 \leq C_i,L_i \leq 10^3
0≤Ci,Li≤103。
【分析】
代码解释
1、输入处理:
读取农场数量 N。
读取每个农场的奶牛数量 C[i]。
读取道路信息,构建邻接表 adj。
2、第一次 DFS (dfs1):
计算以每个节点 u 为根的子树中的 dp[u] 和 size[u]。
dp[u] 表示以 u 为根的子树中,所有奶牛到 u 的总路程。
size[u] 表示以 u 为根的子树中,奶牛的总数量。
3、第二次 DFS (dfs2):
通过换根 DP 计算每个节点作为集会地点时的不方便值。
换根公式:dp[v] = dp[u] - size[v] * L + (size[1] - size[v]) * L。
更新最小不方便值 min_inconvenience。
4、输出结果:
输出最小的不方便值。
//【参考代码】
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 5;
vector<pair<int, int>> adj[MAXN]; // 邻接表存储树
ll dp[MAXN]; // dp[u]: 以 u 为根的子树中,所有奶牛到 u 的总路程
ll size[MAXN]; // size[u]: 以 u 为根的子树中,奶牛的总数量
ll C[MAXN]; // C[u]: 节点 u 的奶牛数量
ll min_inconvenience = 1e18; // 最小不方便值
// 第一次 DFS,计算 dp[u] 和 size[u]
void dfs1(int u, int parent) {
size[u] = C[u];
for (int i = 0; i < adj[u].size(); i++) { // 使用标准 for 循环
int v = adj[u][i].first;
int L = adj[u][i].second;
if (v == parent) continue;
dfs1(v, u);
size[u] += size[v];
dp[u] += dp[v] + size[v] * L;
}
}
// 第二次 DFS,换根 DP,计算每个节点作为集会地点时的不方便值
void dfs2(int u, int parent) {
min_inconvenience = min(min_inconvenience, dp[u]);
for (int i = 0; i < adj[u].size(); i++) { // 使用标准 for 循环
int v = adj[u][i].first;
int L = adj[u][i].second;
if (v == parent) continue;
// 换根操作
dp[v] = dp[u] - size[v] * L + (size[1] - size[v]) * L;
dfs2(v, u);
}
}
int main() {
int N;
cin >> N;
// 输入每个农场的奶牛数量
for (int i = 1; i <= N; i++) { // 使用标准 for 循环
cin >> C[i];
}
// 输入道路信息,构建邻接表
for (int i = 1; i <= N - 1; i++) { // 使用标准 for 循环
int A, B, L;
cin >> A >> B >> L;
adj[A].push_back({B, L});
adj[B].push_back({A, L});
}
// 第一次 DFS,计算 dp 和 size
dfs1(1, -1);
// 第二次 DFS,换根 DP,计算最小不方便值
dfs2(1, -1);
// 输出结果
cout << min_inconvenience << endl;
return 0;
}
更多推荐
所有评论(0)