问题描述:树的直径
输入格式:输入的第一行包含一个整数n,表示树中的点数。接下来n-1行,每行3个正整数,表示连同的两点及边的权值。
输出格式:输出1行,包含一个整数,表示树的直径。
思路
这道题的话,要我们求的是树的直径,所以我们首先要明白什么是树的直径:一棵树上最远的两个点间的距离
一说到最远,那就要想到遍历,一说到遍历,那就又要想到深度优先和广度优先,结合题意,要求的是最远的距离,所以我们用的是深度优先搜索(dfs)
那究竟要怎么实施呢,其实求树的直径有一个很简单的方法(我也是从csdn各位大佬那里学来的),就是做两遍dfs即可:第一次dfs:任选一个点为起点,找出距其最远的点(该点即为其中一个边界点),第二次dfs:以该边界点为起点,找出距其最远的点(该点即为领一个边界点),这两点间的距离即为树的直径。
这个理论的证明,我就不写了,自己想一想是可以想明白的喔~
有了这个思路,我们下面要做的dfs了,首先解决存储结构的问题
我的第一想法是用二维数组,不过很快,这个念头就被打消了:
数据规模和约定
n<10^5
这样是很费空间的,那我们用什么存储结构呢?我又想到了邻接表,我也确实付出行动了,不是不可以了,只是后来找到了更好用且更简单的,所以它被抛弃了,嘤嘤嘤
最终选定的存储结构即为vector
vector<type> a[n];
这样的好处是什么呢?
1、这其实也是个二维数组,只不过这里只规定了其中一维的长度为n,而另一维度是不确定的,这样就大大地节省了空间的浪费。
2、我用的vector的类型也不是int、char这些喔,我用了type,代表这个类型其实是我自己定义的,因为我们这里涉及到了边和权值,所以我们用结构体来存储会更明了。
好了,那我们来看看完整的定义吧
typedef struct
{
int vex;
int weigh;
}edge;
vector<edge> a[100001];
这样的话,我们就做好了我们数据的存储
下面就是建立这棵树了,既然用了二维数组,那就相当于邻接矩阵的存储形式,也就不多说了,看看代码咯
cin>>n;
int p,q,w;
for(int i=0;i<n-1;i++)
{
cin>>p>>q>>w;
edge e;
e.vex=q;
e.weigh=w;
a[p].push_back(e);
edge eto;
eto.vex=p;
eto.weigh=w;
a[q].push_back(eto);
}
这里要注意的就是,1和2之间有边,不仅要在a[1]后面添加2的相关信息,还要在a[2]的后面添加1的相关信息。
现在的话,我们的准备工作就完全结束了,开始重头戏,dfs,我们要想一下,我们还需要哪些辅助呢?
1、visit数组,用来标记某点是否被访问过,在dfs的过程里这很重要喔,不可或缺
2、dis数组,我们要求的是距离,两次dfs都要求距离,所以我们当然要记录这个量了,那么dis[i]代表什么呢,代表的就是i到所求点的距离,(这个所求点两次课是不同的,我们只要中间清空一次dis数组即可,没必要用二维数组的喔)
那下面简单说一下dfs的思想好了
这道题的话,我们不需要对整棵树进行dfs,只需要对某一点出发,遍历和它相关的即可,也就是说:假设我们第一次选的点为1(随机选的第一个点),那我们要遍历的就是以1为起点,与其相连的边。
那怎么记录距离呢?这个点其实困了我一段时间,其实就是与它相邻的上一个点到1的距离加上它与该点间的权值
想到这里呢,其实dfs的思想就出来了,代码也可以有了,那我想插播一下我的一个小错误:
我按这种思路写了代码
for(it=a[i].begin();it!=a[i].end();it++)
it为vector的迭代器,用这样的方式来遍历与1相邻的点,可是后来发现,这样的方式,只能进到一次最深层,他出不来!!!困了我好久
后来发现这样的写法错误在于:每一次dfs压栈,就会破坏原来的迭代,就算弹栈,迭代器不够聪明啊,它回不去了,他找不到了,所以就进不到1的第二个相邻点
所以正确的遍历写法为:
for(int i=0;i<a[n].size();i++)
好了,说到这里,这道题我遇到的坑都讲完了,看代码吧
#include <bits/stdc++.h>
using namespace std;
typedef struct
{
int vex;
int weigh;
}edge;
int n;
int maxn=0;int temp;
vector<edge> a[100001];
int index;
bool visit[100001];
int dis[100001];
void dfs(int n);
bool cmp(int a,int b)
{
return a>b;
}
vector<edge>::iterator it;
int main()
{
cin>>n;
int p,q,w;
for(int i=0;i<n-1;i++)
{
cin>>p>>q>>w;
edge e;
e.vex=q;
e.weigh=w;
a[p].push_back(e);
edge eto;
eto.vex=p;
eto.weigh=w;
a[q].push_back(eto);
}
/*
for(int i=1;i<=n;i++)
{
cout<<i<<":";
for(it=a[i].begin();it!=a[i].end();it++)
{
cout<<(*it).vex<<" ";
}
cout<<endl;
}
*/
memset(dis,0,sizeof(dis));
memset(visit,0,sizeof(visit));
visit[1]=1;
dfs(1);
//cout<<"over"<<endl;
for(int i=2;i<=n;i++)
{
if(dis[i]>maxn)
{
maxn=dis[i];
temp=i;
}
}
//cout<<maxn<<" "<<temp<<endl;
memset(dis,0,sizeof(dis));
memset(visit,0,sizeof(visit));
visit[temp]=1;
dfs(temp);
sort(dis,dis+n+1,cmp);
cout<<dis[0]<<endl;
return 0;
}
void dfs(int n)
{
//cout<<n<<endl;
//index=n;
for(int i=0;i<a[n].size();i++)
{
if(visit[a[n][i].vex]==0)
{
visit[a[n][i].vex]=1;
dis[a[n][i].vex]=dis[n]+a[n][i].weigh;
dfs(a[n][i].vex);
//visit[(*it).vex]=0;
//cout<<"jin"<<endl;
}
}
//cout<<n<<"over"<<endl;
}