题目让从一棵树上找到一个节点,使得其它所有节点到该节点的距离之和最短。若存在不只一个这样的节点,按照节点编号从小到大输出。
两次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; }