参考杜宇飞神牛~http://hi.baidu.com/billdu/blog/item/6ef3e5029ce7d586d43f7cdb.html
题目大意:给一个树,删除其中一个点就会形成一个森林,点的平衡度为删除了这个节点后,所形成多个树,其中组成树的节点最多,节点个数就是那个平衡度。
要你求出最小平衡度,输出这个节点和平衡度,要是有多个节点的平衡度一样,输出节点序号最小。
解题思路,树形dp
balance[i]表示i结点的平衡度
balance[i] = max(node(k)), node(k)表示以i的孩子结点k为根的子树的总结点个数, 其中i为整棵树的根结点
可以规定节点1为这棵树的根结点,进行深度遍历,那么就形成了一个有向树, 在深度遍历的过程中,求出每个结点的出度,根据出度进行拓扑排序,将出度为0的点入队列
深度遍历的过程中求出以每个结点为根的子树的总个数node[k],blanance[k]初始化为num - node[k](num为整棵树的总结点个数)
遍历完毕后,按拓扑排序求balance[i] = max(node[k],balance[i]) ,k为i的孩子结点
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
struct nodes
{
int u, next;
};
const int maxn = 20010;
int t, e, num, node[maxn], n, parent[maxn], balance[maxn], degree[maxn], head[maxn];
nodes edge[maxn*10];
queue<int> q;
void addEdge(int u, int v);
void dfs(int u, int pre);
int main()
{
scanf("%d", &t);
while(t-- != 0)
{
memset(node, 0, sizeof(node));
memset(balance, 0, sizeof(balance));
memset(degree, 0, sizeof(degree));
memset(head, -1, sizeof(head));
e = 0;
while(!q.empty())
q.pop();
scanf("%d", &num);
for(int i = 0; i < num - 1; i++)
{
int u, v;
scanf("%d %d", &u, &v);
addEdge(u, v);
}
int ans = 0x7fffffff, tnode;
dfs(1, -1);
while(!q.empty())
{
int u = q.front();
q.pop();
if(ans > balance[u])
{
ans = balance[u];
tnode = u;
}
else if(ans == balance[u])
tnode = min(tnode, u);
if(parent[u] != -1)
{
balance[parent[u]] = max(balance[parent[u]], node[u]);
degree[parent[u]]--;
if(degree[parent[u]] == 0)
q.push(parent[u]);
}
}
printf("%d %d\n", tnode, ans);
}
return 0;
}
void addEdge(int u, int v)
{
edge[e].u = v;
edge[e].next = head[u];
head[u] = e++;
edge[e].u = u;
edge[e].next = head[v];
head[v] = e++;
}
void dfs(int u, int pre)
{
parent[u] = pre;
node[u] = 1;
if(pre != -1)
degree[pre]++;
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].u;
if(v != pre)
{
dfs(v, u);
node[u] += node[v];
}
}
balance[u] = num - node[u];
if(degree[u] == 0)
q.push(u);
}