1. 程式人生 > >洛谷P3884 二叉樹問題

洛谷P3884 二叉樹問題

題目描述

如下圖所示的一棵二叉樹的深度、寬度及結點間距離分別為:

深度:\(4\) 寬度:\(4\)(同一層最多結點個數)

結點間距離: \(⑧→⑥為8 (3×2+2=8)\)

\(⑥→⑦為3 (1×2+1=3)\)

注:結點間距離的定義:由結點向根方向(上行方向)時的邊數\(×2\)

與由根向葉結點方向(下行方向)時的邊數之和。

輸入輸出格式

輸入格式:

輸入檔案第一行為一個整數\(n(1≤n≤100)\),表示二叉樹結點個數。接下來的\(n-1\)行,表示從結點\(x\)到結點\(y\)(約定根結點為\(1\)),最後一行兩個整數\(u、v\),表示求從結點\(u\)到結點\(v\)

的距離。

輸出格式:

三個數,每個數佔一行,依次表示給定二叉樹的深度、寬度及結點\(u\)到結點\(v\)間距離。

輸入輸出樣例

輸入樣例#1:

10                                
1 2                            
1 3                            
2 4
2 5
3 6
3 7
5 8
5 9
6 10
8 6

輸出樣例#1:

4
4
8

思路:對於第一個子問題,就是找樹上最深的點,一遍\(dfs\)即可實現,對於第二個子問題,就是看看相同深度的點數目的最大值是多少,對於對三個子問題,就是通過\(LCA\)

求兩點間的樹上距離。

程式碼:

#include<cstdio>
#include<algorithm>
#define maxn 107
using namespace std;
int f[maxn][7],n,x,y,js[maxn],maxx,head[maxn],num,d[maxn],zrj;
struct node {
  int v,nxt;
}e[maxn<<1];
inline void ct(int u, int v) {
  e[++num].v=v;
  e[num].nxt=head[u];
  head[u]=num;
}
void dfs(int u, int fa) {
  for(int i=head[u];i;i=e[i].nxt) {
    int v=e[i].v;
    if(v!=fa) {
      f[v][0]=u;
      d[v]=d[u]+1;
      maxx=max(maxx,d[v]);
      dfs(v,u);
    }
  }
}
inline int lca(int a, int b) {
  if(d[a]>d[b]) swap(a,b);
  for(int i=6;i>=0;--i) 
  if(d[a]<=d[b]-(1<<i)) b=f[b][i];
  if(a==b) return a;
  for(int i=6;i>=0;--i)
  if(f[a][i]!=f[b][i]) a=f[a][i],b=f[b][i];
  return f[a][0];
}
int main() {
  scanf("%d",&n);
  for(int i=1,u,v;i<n;++i) {
    scanf("%d%d",&u,&v);
    ct(u,v);ct(v,u);
  }
  dfs(1,0);
  for(int i=1;i<=n;++i) js[d[i]]++;
  for(int i=1;i<=maxx;++i) zrj=max(zrj,js[i]);
  for(int j=1;j<=6;++j)
  for(int i=1;i<=n;++i)
  f[i][j]=f[f[i][j-1]][j-1];
  scanf("%d%d",&x,&y);
  printf("%d\n%d\n%d\n",maxx+1,zrj,(d[x]-d[lca(x,y)])*2-d[lca(x,y)]+d[y]);
  return 0;
}