题目链接:
POJ 1655 Balancing Act
题意:
给一个
n
个结点和
求所有结点中平衡值的最小值。
数据范围:
n≤2∗104
分析:
比较简单的树型dp。
对每个节点记录以它为根的子树的结点数量,
dfs
更新即可,再判断下父亲结点之上的结点数量,根节点特判下就好了。
时间复杂度:
O(n+m)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <climits>
#include <cmath>
#include <ctime>
#include <cassert>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
using namespace std;
typedef long long ll;
const int MAX_N = 20010;
int T, n, total;
int head[MAX_N], num[MAX_N], ans[MAX_N];
struct Edge {
int v, next;
} edge[MAX_N * 2];
void AddEdge(int u, int v)
{
edge[total].v = v;
edge[total].next = head[u];
head[u] = total++;
}
void dfs(int u, int p)
{
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].v;
if (v == p) continue;
dfs(v, u);
num[u] += num[v];
ans[u] = max(ans[u], num[v]);
}
num[u]++; // 自身还有一个结点
if (u != 1) ans[u] = max(ans[u], n - num[u]);
//printf("num[%d] = %d ans[%d] = %d\n", u, num[u], u, ans[u]);
}
void wyr()
{
memset(ans, 0, sizeof(ans));
memset(num, 0, sizeof(num));
dfs(1, -1);
int Min = INT_MAX, id = 0;
for (int i = 1; i <= n; ++i) {
if (ans[i] < Min) {
Min = ans[i];
id = i;
}
}
printf("%d %d\n", id, Min);
}
int main()
{
scanf("%d", &T);
while (T--) {
memset(head, -1, sizeof(head));
total = 0;
scanf("%d", &n);
for (int i = 1; i < n; ++i) {
int u, v;
scanf("%d%d", &u, &v);
AddEdge(u, v);
AddEdge(v, u);
}
wyr();
}
return 0;
}