P3884 [JLOI2009]二叉树问题(洛谷)

题目描述

如下图所示的一棵二叉树的深度、宽度及结点间距离分别为:

深度: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。但对于此题,已经知道根节点始终是1且各节点连接信息表现出来的情况下,可以直接利用邻接矩阵+dfs从根节点搜,保存各节点的深度信息即可。

 

       具体步骤如下:
       1.先使用邻接矩阵(即二维数组)储存各节点长度关系,如a[i][j]储存第i和第j个结点的距离,若两节点不连接,则设置为0。

       2.首先,从根节点(1)开始往下搜,用dfs遍历所有的结点,在遍历的同时用depth数组储存各节点的深度,如根节点1的深度为1,每访问到一个节点就保存深度信息。

       3.有了结点信息后,进行排序求出最大深度。另外,通过统计相同的深度的节点数量即可确定树的最大宽度。

       4.接下来,开始对起始要搜索的点dfs,当碰见一个节点,进行深度比较,若深度大于该节点则路程加2,若小于该节点则路程加1,知道遇到终止点。、

 

代码

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 using namespace std;
 5 
 6 //原本的打算是先建立一棵树,再进行dfs 
 7 //但对于此题,已经知道根节点始终是1且各节点连接信息表现出来的情况下,可以直接利用邻接矩阵+dfs从根节点搜,保存各节点的深度信息即可 
 8 #define INF 999999999
 9 int depth[101];    //记录各节点的深度信息 
10 int broad[100];    //记录宽度(dfs后记录) 
11 int map[101][101]={0};        //邻接矩阵,0代表无连接,1代表连接 
12 int n=0;
13 int flag[101]={0};        //存储各节点是否被访问的信息 
14 int u=0,v=0;        //起始和目标 
15 int minsum=INF;
16 
17 bool cmp(int a,int b){
18     return a>b;
19 }
20 void dfs(int cur,int dep){
21     flag[cur]=1;
22     depth[cur]=dep;
23 //    cout<<"cur:"<<cur<<" depth:"<<depth[cur]<<endl;
24     
25     for(int i=1;i<=n;i++){
26         if(flag[i]==1)    continue;        //防止来回搜死循环 
27         if(map[cur][i]!=0){
28             dfs(i,dep+1);
29         }
30         flag[i]=0;    //回溯 
31     }
32     return ; 
33 }
34 void dfs1(int cur,int sum){        //cur是结点编号,sum为当前距离 
35 //    cout<<"cur:"<<cur<<" sum:"<<sum<<endl;
36     flag[cur]=1;
37     if(sum>=minsum){
38         return ;        //剪枝 
39     }
40     if(cur==v){
41         if(sum<minsum){
42             minsum=sum;
43         } 
44         return;        //找到并返回,更新minsum 
45     }
46     
47     for(int i=1;i<=n;i++){
48         if(flag[i]==1)    continue;
49         if(map[cur][i]!=0){
50             if(depth[i]>depth[cur]){
51                 dfs1(i,sum+1);        //向下搜 
52             }else if(depth[i]<depth[cur]){
53                 dfs1(i,sum+2);        //向上搜 
54             }
55         }
56         flag[i]=0;    //回溯 
57     }
58     
59     return;     
60 }
61 int main(){
62     cin>>n;
63     for(int i=1;i<=n-1;i++){
64         int m,k;
65         cin>>m>>k;
66         map[m][k]=map[k][m]=1;
67     }
68     cin>>u>>v;
69     
70     dfs(1,1);
71     int maxdepth=0;        //最大深度 
72     int maxbroad=0;        //最大宽度 
73     for(int i=1;i<=n;i++){
74         if(depth[i]>maxdepth){
75             maxdepth=depth[i];
76         }
77         broad[depth[i]]++;        //同一深度的结点数量累加 
78     }
79     sort(broad,broad+n,cmp);
80     maxbroad=broad[0];
81     
82     //上述进行完树的深度和宽度查询后,下面开始距离搜索
83     memset(flag,0,sizeof(flag));
84     dfs1(u,0); 
85     cout<<maxdepth<<endl<<maxbroad<<endl<<minsum;
86     return 0;
87 }

 

posted @ 2020-03-27 11:02  neverstopcoding  阅读(235)  评论(0编辑  收藏  举报