想了很久, 以为是网络流最大流, 后来建模建不出来, 无奈。

后来看了 https://blog.csdn.net/hao_zong_yin/article/details/79441180

感觉思路很巧妙。

首先题目等价于让每条边经过的次数最多。

那么假设一条边点a到点b, 假设以b为根节点的子树中的节点数为pb, 那么剩下的

以以b为根节点的子树中的节点数为pa

我们假设pa > pb

那么从a这边去b这边, 最多只能走pb次, 因为不能到同一个点,b那边最多就pb个点

如果经过次数大于pb的话就说明肯定b那边的点至少一个点经过了两次以上

那么b这边最多去a那边也是pb次, 这次是因为起点就这么多个点。

所以这条边走过的次数就是pb * 2, 算上权值就是pb * 2 * cost

那么我们就可以得出, 对于一条边u1, u2, 那么经过这条边的最大权值为

min(dp[u1], n - dp[u1]) * cost * 2

dp[u]表示以u为根节点的子树中节点的个数。

所以我们每条边都加上最大权值即为答案

最后注意要开 long long。

#include<cstdio>
#include<algorithm>
#include<vector>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
using namespace std; typedef long long ll;
const int MAXN = 112345;
struct node { int v, w; };
vector<node> g[MAXN];
int n, dp[MAXN];
ll ans; void dfs(int u, int fa)
{
dp[u] = 1;
REP(i, 0, g[u].size())
{
int v = g[u][i].v, w = g[u][i].w;
if(v == fa) continue;
dfs(v, u);
ans += min(dp[v], n - dp[v]) * w * 2;
dp[u] += dp[v];
}
} int main()
{
int T, kase = 0;
scanf("%d", &T); while(T--)
{
scanf("%d", &n);
REP(i, 0, n) g[i].clear();
REP(i, 0, n - 1)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
u--; v--;
g[u].push_back(node{v, w});
g[v].push_back(node{u, w});
} ans = 0;
dfs(0, -1);
printf("Case #%d: %lld\n", ++kase, ans);
} return 0;
}
05-23 12:55