才过了几天,树的直径的东西就全忘了,今天写了一道题,完全不会……哎。。。是时候马克了
还是大水题
【题目】
第2到N行的第一个数分别表示第2~N号节点所连接的节点编号,第二个数表示这两个点之间的距离。
输出:从第1到N行一行一个数字,表示这个点到距离它最远的点的距离是多少。
【思路】
这个想法还是参考了同学的算法的,网上搜到的都是树形DP+DFS,习惯了用BFS就不想再用DFS了(其实是因为我把DFS给忘了→_→而且你居然这么认真地发现了括号里居然有句话)。
首先树的直径指的是途中两个最远的节点之间的距离,要想找到这个距离,先从图中任意一点找距离此点 的最长距离的点M,然后找距M最远的点N,M~N之间的距离就是树的直径。而且图中任意一个点到这两个节点的距离其中必有一个距离是这个点到其它点的距离的最大值,即距离要找的点最远的点一定出现在树的直径的两个端点之一。
所以我们可以先找到这两个端点,然后用dis数组来分别保存这两个端点到其它点的距离,然后按点的序号从小到大输出这两个距离之间更大的就好了!这道题逆着想,就会容易很多,如果正着想用bfs逐个查询每个端点的最大距离的话是会超时的!
【代码】
#include
#include
#include
#define MAXN 99999//这个数是我瞎定的,想要弄小点也可以,不过要超过题目的最小要求啊
using namespace std;
struct node{ int x,y,z,next; } a[MAXN];//保存节点信息,next是记录与之相邻的节点的位置信息
int n,cnt,head[MAXN];//head用来记录每个节点的位置,简单理解就相当于链表指针
int dis[MAXN],mp;//dis储存位置信息,mp表示最远端点的序号
void add(int i,int b,int c);//添加每个节点的信息,至于为什么能用这种方法能将next指向与之相邻的节点我也不知道→_→套用这样的格式就好
void bfs(int src);
int main()
{
while(scanf("%d",&n)!=EOF)
{
cnt=0;
memset(head,-1,sizeof(head));
for(int i=2;i<=n;i++)
{
int b,c;
scanf("%d%d",&b,&c);
add(i,b,c);
}
bfs(1);
bfs(mp);//两个连续的bfs是要找到树的直径的第一个端点并更新此端点到任意节点的距离
int dis2[n+1];
for(int i=1;i<=n;i++)
{
dis2[i]=dis[i];//把这些距离储存起来
}
bfs(mp);//找另一端点到任意节点的距离,此时mp已被重置为另一端点
for(int i=1;i<=n;i++)
{
printf("%d\n",dis[i]>dis2[i]?dis[i]:dis2[i]);//比较后输出结果
}
}//我也不知道为什么,突然想在这一行加一个注释
}
void add(int i,int b,int c)
{
a[cnt].x=i;a[cnt].y=b;a[cnt].z=c;
a[cnt].next=head[i];
head[i]=cnt++;
a[cnt].x=b;a[cnt].y=i;a[cnt].z=c;
a[cnt].next=head[b];
head[b]=cnt++;
}
void bfs(int src)
{
int minn=0;
memset(dis,0,sizeof(dis));
queueq;
int vis[MAXN]={0};
vis[src]=1;
mp=src;
q.push(src);
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=head[x];i!=-1;i=a[i].next/*指向下一个*/)
{
int y=a[i].y;
if(!vis[y])
{
vis[y]=1;
dis[y]=dis[x]+a[i].z;
q.push(y);
if(minn