题目描述
给一棵树,求树的重心
名词解释
删除一个点,使得形成的多棵树中节点数最大的树的节点数最小。
这个点即为树的重心。
输入格式
一行一个整数n,即树的节点个数(n<=5*10^4)
接下来n-1行,每行两个整数,表示树上一条边。
输出格式
如果有多个重心,则按编号从小到大依次输出
样例输入
6
1 2
2 3
2 5
3 4
3 6
样例输出
2 3
提示
卡vector,建议用手写的链式前向星或邻接表
思路:模板直接写即可,两种做法
1.两次扫描法
#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <iomanip>
#include <stdio.h>
#include <string>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
using namespace std;
const int N = 5e4 + 10;
int n, h[N], ne[N<<2], e[N<<2];
int idx;
void add(int x, int y)
{
e[idx] = y, ne[idx] = h[x], h[x] = idx ++;
e[idx] = x, ne[idx] = h[y], h[y] = idx ++;
}
int sum[N];
int vis[N];
void dp(int x)
{
vis[x] = 1;
sum[x] = 1;
for(int i = h[x]; ~i; i = ne[i])
{
int ver = e[i];
if(vis[ver] == 0)
{
dp(ver);
sum[x] += sum[ver];
}
}
}
int ans[N], minn = 1<<30;
void dfs(int x)
{
vis[x] = 1;
int tmp1 = n - sum[x];
for(int i = h[x]; ~i; i = ne[i])
{
int ver = e[i];
if(vis[ver] == 0)
{
tmp1 = max(tmp1, sum[ver]);
dfs(ver);
}
}
ans[x] = tmp1;
minn = min(minn, tmp1);
}
int main()
{
ios::sync_with_stdio(false), cin.tie(0);
while(cin >> n && n)
{
idx = 0;
memset(h, -1, sizeof h);
memset(sum, 0, sizeof sum);
memset(vis, 0, sizeof vis);
memset(ans, 0, sizeof ans);
for(int i = 1; i < n; i++)
{
int x, y;
scanf("%d %d", &x, &y);
add(x, y);
}
dp(1);
memset(vis, 0, sizeof vis);
dfs(1);
bool flag = 0;
for(int i = 1; i <= n; i++)
{
if(ans[i] == minn && flag == 0) cout << i, flag = 1;
else if(ans[i] == minn) cout << " " << i;
}
cout << endl;
}
return 0;
}
2.直接dp
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=100010;
int head[maxn],next[maxn],To[maxn],cnt;
int son[maxn],sz[maxn];
int q[maxn],tot,n,root;
void add(int u,int v) {
next[++cnt]=head[u];
head[u]=cnt;
To[cnt]=v;
}
void dfs(int u,int fa) {
sz[u]=1;
for(int i=head[u]; i; i=next[i]) {
int v=To[i];
if(v!=fa) {
dfs(v,u);
sz[u]+=sz[v];
son[u]=max(sz[v],son[u]);
}
}
son[u]=max(son[u],n-sz[u]);
if(son[u]<son[root]) {
root=u;
//重置答案
tot=0;
q[++tot]=u;
} else if(son[u]==son[root]) q[++tot]=u;
}
int main() {
while(~scanf("%d",&n)) {
memset(son,0,sizeof(son));
memset(sz,0,sizeof(sz));
memset(head,0,sizeof(head));
int u,v;
tot=cnt=0;
for(int i=1; i<n; i++) {
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
root=0;
son[root]=INF;
dfs(1,0);
sort(q+1,q+tot+1);
printf("%d",q[1]);
for(int i=2; i<=tot; i++)
printf(" %d",q[i]);
printf("\n");
}
return 0;
}