存储结构
const int inf=1e9;
const int maxn=10005;
const int maxm=20005;
typedef struct{
int u,v,next;
}Edge;
Edge edge[maxm];
int head[maxn],cnt=0;//head[maxn]初始值为-1
int n,m;
void addedge(int u,int v){
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
求树的结点个数
//求树中结点个数
int num=0;
void DFS(int u,int pre){
num+=1;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].next;
if(v==pre) continue;
DFS(v,u);
}
}
树的重心
基本知识
概念: 树的重心也叫树的质心。找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡。
性质:
- 树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有两个重心,他们的距离和一样。
- 把两棵树通过一条边相连,新的树的重心在原来两棵树重心的连线上。
- 一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置。
- 一棵树最多有两个重心,且相邻。
求树的重心(无权)
//求树的重心及距离
int minBlance=inf,g=-1,sumLength;
int dfs(int u,int pre){
int sum=1,maxSub=0;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(v==pre) continue;
int t=dfs(v,u);
maxSub=max(maxSub,t);
sum+=t;
}
maxSub=max(maxSub,n-sum);
if(maxSub<minBlance){
minBlance=maxSub;
g=u;
}
sumLength=sumLength+sum-1;
return sum;
}
求树的重心(结点带权)
//求有权树的重心的及距离
int minBlance=inf,g=-1,sumLength;
int dfs(int u,int pre){
int sum=weight[u],maxSub=0;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(v==pre) continue;
int t=dfs(v,u);
maxSub=max(maxSub,t);
sum+=t;
}
maxSub=max(maxSub,total-sum);
if(maxSub<minBlance){
minBlance=maxSub;
g=u;
}
sumLength=sumLength+sum-weight[u];
return sum;
}
完整代码
无权树
/*
* problem:求无权树的重心
* method:dfs
* date:2020/09/07
*/
#include<iostream>
#include<iomanip>
#include<cmath>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<utility>
#include<cmath>
#define ll long long
using namespace std;
const int inf=1e9;
const int maxn=10005;
const int maxm=20005;
typedef struct{
int u,v,next;
}Edge;
Edge edge[maxm];
int head[maxn],cnt=0;
int n,m;
void addedge(int u,int v){
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
//求树的重心及距离
int minBlance=inf,g=-1,sumLength;
int dfs(int u,int pre){
int sum=1,maxSub=0;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(v==pre) continue;
int t=dfs(v,u);
maxSub=max(maxSub,t);
sum+=t;
}
maxSub=max(maxSub,n-sum);
if(maxSub<minBlance){
minBlance=maxSub;
g=u;
}
sumLength=sumLength+sum-1;
return sum;
}
int main(){
int i,j,a,b;
cin>>n>>m;
memset(head,-1,sizeof(head));
for(i=0;i<m;i++){
cin>>a>>b;
addedge(a,b);
addedge(b,a);
}
dfs(1,-1);//求重心
sumLength=0;
dfs(g,-1);//求距离
cout<<g<<" "<<sumLength<<endl;
return 0;
}
有权树
/*
* problem:求有权树的重心
* method:dfs
* date:2020/09/07
*/
#include<iostream>
#include<iomanip>
#include<cmath>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<utility>
#include<cmath>
#define ll long long
using namespace std;
const int inf=1e9;
const int maxn=10005;
const int maxm=20005;
typedef struct{
int u,v,next;
}Edge;
Edge edge[maxm];
int head[maxn],weight[maxn],total=0,cnt=0;
int n,m;
void addedge(int u,int v){
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
//求有权树的重心的及距离
int minBlance=inf,g=-1,sumLength;
int dfs(int u,int pre){
int sum=weight[u],maxSub=0;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(v==pre) continue;
int t=dfs(v,u);
maxSub=max(maxSub,t);
sum+=t;
}
maxSub=max(maxSub,total-sum);
if(maxSub<minBlance){
minBlance=maxSub;
g=u;
}
sumLength=sumLength+sum-weight[u];
return sum;
}
int main(){
int i,j,a,b;
cin>>n>>m;
memset(head,-1,sizeof(head));
for(i=1;i<=n;i++){
cin>>weight[i];
total+=weight[i];
}
for(i=0;i<m;i++){
cin>>a>>b;
addedge(a,b);
addedge(b,a);
}
dfs(1,-1);//求重心
sumLength=0;
dfs(g,-1);//求最短距离和
cout<<g<<" "<<sumLength<<endl;
return 0;
}