原文:https://blog.csdn.net/aozil_yang/article/details/61926727
题意:
给你一棵包括n 个结点的树,每个结点上住着一个人,每个人都要换房子,但不能有两个人 住在同一个房子,求的所有人的最大路程长度?
思路:
成都2011年区域赛的题目:
感觉正解好巧妙:
最优解肯定是让每一个边尽量走更多次数。
那么我们只需要算一下每个边 走的最大次数是多少即可。
比如说a 这个结点的子树里(包括a) 一共有u 个结点, 那么剩下的有 n-u 个结点。令f 是a的父亲。
那么f到a 这个边最多走min(u,n-u)次,因为要么是所有u结点都出去,要么是所有n-u个结点都进来。 取一个最小值即可。
这样统计每个边次数 乘以边权即可。
#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
#include <algorithm>
#define fi first
#define se second
#define pii pair<int,int>
using namespace std;
const int INF = 0x3f3f3f3f;
typedef long long LL;
const int maxn = 100000+5;
int n,sons[maxn];
LL ans;
vector<pii> G[maxn];
void init(int a){ for(int i = 0; i <= a; ++i) G[i].clear();}
void dfs(int u, int f, int w){
if(G[u].size() == 1&&G[u][0].fi == f){ // 是叶子
sons[u] = 1;
ans += w;
return;
}
sons[u] = 1;
for(int i = 0; i < G[u].size(); ++i){
int v = G[u][i].fi;
if(v != f){
dfs(v, u, G[u][i].se);
sons[u] += sons[v];
}
}
ans += (LL)w * (LL)min(sons[u], n-sons[u]);
}
int main()
{
//freopen("in.txt","r",stdin);
int T; scanf("%d",&T);
int kase = 1;
while(T--){
scanf("%d",&n); init(n);
for(int i = 0; i < n-1; ++i){
int u,v,w; scanf("%d%d%d",&u,&v,&w);
G[u].push_back(make_pair(v, w));
G[v].push_back(make_pair(u, w));
}
ans = 0;
dfs(1, 0, 0);
printf("Case #%d: %lld\n", kase++, ans<<1);
}
return 0;
}