题意:给定一棵树,需要我们求得树的直径 和 直径的数量
思路:
树的直径的求法:
1.两遍dfs,这种方法适合只求 长度数值
2.记录每个节点的 最长叶节点 和 次长叶节点(可能不存在) 的距离
树:-> 递归求解(子树分解)【所以,不能再返回父节点,遍历的时候记得删掉父节点】
1.考虑一下直径可能存在哪里:
1.经过我们设定的根节点
2.不经过我们设定的根节点(一开始没有考虑),但是直径一定是经过某个子树的根节点 所以需要记录所有结点的 次长 和 最长叶节点 距离
所以我们将问题转换为,必须经过我们子树的根节点的直径有多少?
如何保证一定经过子树的根节点? 我们遍历子树的所有分支的根节点,将其 最长叶节点距离 作为根节点的 最长叶节点距离 或者 次长叶节点距离,这样就可以保证一定是经过 子树的根节点的
2.分类统计各种情况下,两个不同子树的最长距离和数量
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i=a;i<b;++i)
const int N=10010;
struct Edge{
int v,w;
Edge(int _v=0,int _w=0){
v=_v,w=_w;
}
};
vector<Edge>edge[N];
void add_edge(int u,int v,int w){
edge[u].push_back(Edge(v,w));
edge[v].push_back(Edge(u,w));
}
int path[N],num[N];//
int maxDis[N],secDis[N];
int maxNum[N],secNum[N];
void dfs(int x,int f){
if(edge[x].size()==1&&edge[x][0].v==f){//防止一开始就是叶节点,直接退出
maxDis[x]=secDis[x]=0;
maxNum[x]=num[x]=1;
path[x]=0;
return;
}
rep(i,0,edge[x].size()){
Edge& e=edge[x][i];
if(e.v==f)continue;
dfs(e.v,x);
if(maxDis[e.v]+e.w>maxDis[x]){
secDis[x]=maxDis[x];
secNum[x]=maxNum[x];
maxDis[x] = maxDis[e.v]+e.w;
maxNum[x] = maxNum[e.v];
}else if(maxDis[e.v]+e.w==maxDis[x]){
maxNum[x] += maxNum[e.v];
}else if(maxDis[e.v]+e.w>secDis[x]){
secDis[x] = maxDis[e.v]+e.w;
secNum[x] = maxNum[e.v];
}else if(maxDis[e.v]+e.w == secDis[x]){
secNum[x] += maxNum[e.v];
}
}
int c1=0,c2=0;
rep(i,0,edge[x].size()){
Edge & e=edge[x][i];
if(e.v==f)continue;
if(maxDis[x]==maxDis[e.v]+e.w){
c1++;
}else if(secDis[x]==maxDis[e.v]+e.w){
c2++;
}
}
//printf("** x:%d c1:%d c2:%d secDis:%d\n",x,c1,c2,secDis[x]);
if(c1>1){//多个分支都有最大距离
path[x]=maxDis[x]*2;
int sum=0;
rep(i,0,edge[x].size()){
Edge& e=edge[x][i];
if(e.v==f)continue;
if(maxDis[x]==maxDis[e.v]+e.w){
num[x]+=sum*maxNum[e.v];
sum+=maxNum[e.v];
}
}
}else if(c1==1&&c2>0){//只有一个最大距离,多个次大距离
path[x]=maxDis[x]+secDis[x];
num[x]=maxNum[x]*secNum[x];
}else{//只有一个最大距离,x是直径的一端
path[x]=maxDis[x];
num[x]=maxNum[x];
}
}
/*
*/
int main(){
int n;
while(scanf("%d",&n)!=EOF){
rep(i,1,n+1){
edge[i].clear();
num[i]=path[i]=maxNum[i]=secNum[i]=maxDis[i]=secDis[i]=0;
}
rep(i,0,n-1){
int u,v,w;
scanf("%d %d %d",&u,&v,&w);
add_edge(u,v,w);
}
dfs(1,0);
// rep(i,1,n+1)printf("*%d maxDis:%d secDis:%d path:%d num:%d mxNm:%d\n",i,maxDis[i],secDis[i],path[i],num[i],maxNum[i]);
int mxDs=0,res=0;
rep(i,1,n+1){
if(path[i]>mxDs){
mxDs=path[i];
res=num[i];
}else if(path[i]==mxDs){
res+=num[i];
}
}
if(n==1)res=1;
printf("%d %d\n",mxDs,res);
}
return 0;
}