想了很久, 以为是网络流最大流, 后来建模建不出来, 无奈。
后来看了 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;
}