题目3
定义树中某结点的平衡为删除该结点后所形成的森林中各树结点数的最大值。如下图左边的树,如果删除其中的一个结点3,则该树变成右边的森林,也就是多棵树,这些树的结点数分别为6,1,1,1,其最大值为6,因此结点3的平衡为6。
在给定一棵树的情况下,求该树中所有结点的最小平衡数。
输入要求:
输入的第一行是一个整数n((1 <= n<= 20),表示测试数据的组数。每一组测试数据的第一行是一个整数m (1 <= m <= 20,000),表示树中的一对结点,其后的N-1行,每一行包含两个整数,表示树中相连的两个结点。树中结点的编号从1开始编号。
输出要求:
对于每一组测试数据输出一行,表示该树中所有结点的平衡数的最小值。
输入样例:
1
9
1 2
1 3
1 4
2 5
3 6
3 7
3 8
4 9
4 10
输出样例:
4
#include <iostream>
#define N 50
using namespace std;
typedef struct tnode
{
int child;//编号
struct tnode* next{NULL};
}ctnode,*childptr;
typedef struct Fnode
{
childptr firstptr{NULL};
int childnum{0};
}fnode;
int dp[N]{0};
int nodesbnum[N];
int dfs(int curnode, fnode nodes[N]) //求以curnode为根结点的总结点数,包括它自身
{
int sum = 1;
childptr p=nodes[curnode].firstptr;
while(p)
{
int nexti = p->child;
sum += dfs(nexti,nodes);
p = p->next;
}
nodesbnum[curnode] = sum;
return sum;
}
void dpbalance(int i, fnode nodes[N])
{
int max_nodes = 0;
childptr p = nodes[i].firstptr;
while (p)
{
int nexti = p->child;
max_nodes = max(max_nodes, nodesbnum[nexti]);
p = p->next;
}
max_nodes = max(max_nodes, nodesbnum[1] - nodesbnum[i]);//是【树根节点】的所有结点数减去该结点的结点数
dp[i] = max_nodes;
}
int main()
{
fnode nodes[N]{}; int n;cout << "input n:"; cin >> n;
int m, mindp{8888};
for (int i = 1; i <= n; i++){
mindp = 8888;cout << "input m:";cin >> m;int maxn{ 0 };
for (int i = 1; i <= m; i++)
{
int root, child; childptr p, pr;
cin >> root >> child; if (!nodes[root].firstptr) nodes[root].firstptr = new ctnode{ child };
else
{
p = pr = nodes[root].firstptr;
while(pr)
{
p = pr; pr = pr->next;
}
if (!pr)
{
pr = new ctnode;
pr->child = child;
p->next = pr;
}
}
if (child > maxn) maxn = child;
}
dfs(1, nodes);
for (int i = 1; i <= maxn; i++)
{
dpbalance(i, nodes);
if (mindp > dp[i]) mindp = dp[i];
}
cout << "最小平衡值为:" << mindp;
}
return 0;
}