Uva1669交换房子——思维

原文: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;
}

猜你喜欢

转载自blog.csdn.net/CY05627/article/details/93505984