树的重心
树的重心是指树上一点,去掉后最大子树可以取得最小值的点。
求解方法:
树的重心定义:去掉该点后最大子树大小不超过n/2。重心为1
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 100010
struct edge
{
int to;
int nxt;
}e[maxn];
int head[maxn],k=0;
bool vis[maxn];
int Size[maxn],ans=0x3f3f3f3f;
int maxpart[maxn];
int n;
void add(int u,int v)
{
e[k].to=v;
e[k].nxt=head[u];
head[u]=k++;
}
void dfs(int u)
{
vis[u]=1;
Size[u]=1;
maxpart[u]=0;
for(int i=head[u];~i;i=e[i].nxt)
{
int v=e[i].to;
if(vis[v]) continue;
dfs(v);
Size[u]+=Size[v];
maxpart[u]=max(maxpart[u],Size[v]);
}
maxpart[u]=max(maxpart[u],n-Size[u]);
if(maxpart[u]<ans)
ans=maxpart[u];
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d",&n);
int u,v;
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs(1);
for(int i=1;i<=n;i++)
{
if(maxpart[i]==ans) printf("%d\n",i);
}
dfs(1);
}
树的直径
指树上最远两点的距离
方法:先随便找个点,找到离他最远的点,再在那个最远的点上找一次最远的点,这两个点之间的距离就是直径。
代码:
#include<bits/stdc++.h>
#define maxn 100005
using namespace std;
int n, m;
int dep[maxn], dis[maxn], l = 1, r = 0;
int res, ans;//res为找到的最远点,ans为直径
bool vis[maxn];
struct edge
{
int to;
int w;
int nxt;
}e[maxn];
int k = 0, head[maxn];
void add(int u,int v,int w)
{
e[k].to=v;
e[k].w=w;
e[k].nxt=head[u];
head[u]=k++;
}
void bfs(int u)
{
memset(dis, 0, sizeof dis);//调用两次,必须清空
memset(vis, 0, sizeof vis);
queue<int> q;
q.push(u);
vis[u] = 1;
while(q.size())
{
int p = q.front();
q.pop();
if(dis[p] > ans)//找到了距离更远的
ans = dis[p], res = p;//可以直接更新
for(int i = head[p]; ~i; i = e[i].nxt)
{
int v = e[i].to, w = e[i].w;
if(!vis[v])
{
vis[v] = 1;
dis[v] = dis[p] + w;//计算dis,在下一次取出来时再和ans作比较
q.push(v);
}
}
}
}
int main()
{
memset(head, -1, sizeof head);
scanf("%d%d", &n, &m);
int u, v, w;
char op;
for(int i = 1; i <= m; i++)
{
scanf("%d%d%d %c", &u, &v, &w, &op);
add(u, v, w);
add(v, u, w);
}
bfs(1);//随便一个点
ans = 0;
bfs(res);//第二次
printf("%d\n", ans);
return 0;
}