树的直径:指的是树上相隔最远的两点之间的距离,具体求法的话,从任意一结点开始
,先找出离这个结点最远的结点(bfs),然后再找出离这个顶点最远的节点(bfs),求出
的距离就是直径
树的重心:树的重心是指这样的一个节点,使得以这个节点为根的子树的节点数最大最小
比如说在一棵树中,若以1为根 子树的大小分别是:2,2,2 ,若以2为根,子树的大小分
别是3,2,1.这根数时候的重心就是1,因为1中字树含有结点数最大时2,而另一个为3。
求法:
树的重心是对无根树来说的,因此我们可以任取一个节点使其成为有根树,用一个数组son[i]表示
以i为根的字数大小。我们可以知道在树上的任意一个节点可以分为他的子树和除去子树外剩余的节点
我们可以通过dfs先找出以i为根的子树最大值是多少。然后再和除去以i为根的树就是剩余节点,这些节点也可以
看作一个子树。然后在和这个比较即可
列题:https://vjudge.net/problem/POJ-1655
模板题求出树的重心,然后求出最大子树
#include<iostream> #include<algorithm> #include<vector> using namespace std; const int maxn=2e5+10; vector<int>q[maxn]; int d[maxn],n; int minnode,minbalance; void dfs(int u,int fa) { d[u]=1; int maxsubtree=0; for(int i=0;i<q[u].size();i++) { int v=q[u][i]; if(v==fa) continue; dfs(v,u); d[u]+=d[v]; maxsubtree=max(maxsubtree,d[v]); } maxsubtree = max(maxsubtree,n - d[u]); // "upside substree with (N - d[node]) nodes" if (maxsubtree < minbalance){ minbalance = maxsubtree; minnode = u; } } int main() { int t; cin>>t; while(t--) { cin>>n; for(int i=1;i<n;i++) { int a,b; cin>>a>>b; q[a].push_back(b); q[b].push_back(a); } minnode=0; minbalance=0x3f3f3f; dfs(1,0); cout<<minnode<<" "<<minbalance<<endl; for(int i=1;i<=n;i++) q[i].clear(); } return 0; }
练习题:
POJ 1849
CF 734E
POJ 1985
POJ 1655
HDU 2196
CF 686D