POJ 4045 Power Station(据说是:树形dp)

题目让从一棵树上找到一个节点,使得其它所有节点到该节点的距离之和最短。若存在不只一个这样的节点,按照节点编号从小到大输出。

两次dfs就好了。

#pragma warning(disable:4996)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <set>
using namespace std;
typedef long long LL;
const int N = 50010;
int n, I, R;
LL ans;
int fst[N], nxt[N], to[N], e;
bool vis[N];
int cnt[N];//cnt为子树中的节点个数(包括自己)
LL sum[N];//表示i与其他所有节点距离的和
set<int>s;

void add(int u, int v) {
	to[e] = v;
	nxt[e] = fst[u];
	fst[u] = e++;
}

void dfs(int u,LL d) {
	vis[u] = true;
	//dis[u] = d;
	cnt[u] = 1;
	sum[1] += d;
	for (int i = fst[u]; i != -1; i = nxt[i]) {
		int v = to[i];
		if (!vis[v]) {
			dfs(v, d + 1);
			cnt[u] += cnt[v];
		}
	}
}

void DFS(int u) {
	vis[u] = true;
	ans = min(ans, sum[u]);
	for (int i = fst[u]; i != -1; i = nxt[i]) {
		int v = to[i];
		if (!vis[v]) {
			sum[v] = sum[u] + n - 2 * cnt[v];
			DFS(v);
		}
	}
}

int main() {
	//freopen("in.txt", "r", stdin);
	int t; scanf("%d", &t);
	while (t--) {
		e = 0;
		memset(fst, -1, sizeof fst);
		scanf("%d %d %d", &n, &I, &R);
		for (int i = 1; i < n; i++) {
			int u, v;
			scanf("%d %d", &u, &v);
			add(u, v);
			add(v, u);
		}
		memset(vis, false, sizeof vis);
		memset(sum, 0, sizeof sum);
		dfs(1, 0LL);
		memset(vis, false, sizeof vis);
		ans = 0x3f3f3f3f;
		DFS(1);

		printf("%I64d\n", (LL)(ans*I*I*R));
		int flag = 1;
		for (int i = 1; i <= n; i++) {
			if (ans == sum[i]) {
				if (flag > 1)printf(" ");
				flag++;
				printf("%d", i);
			}
		}
		printf("\n\n");
	}
	return 0;
}


你可能感兴趣的:(POJ 4045 Power Station(据说是:树形dp))