主要是利用了反证法:
假设 s-t这条路径为树的直径,或者称为树上的最长路
现有结论,从任意一点u出发搜到的最远的点一定是s、t中的一点,然后在从这个最远点开始搜,就可以搜到另一个最长路的端点,即用两遍广搜就可以找出树的最长路
证明:
1 设u为s-t路径上的一点,结论显然成立,否则设搜到的最远点为T则
dis(u,T) >dis(u,s) 且 dis(u,T)>dis(u,t) 则最长路不是s-t了,与假设矛盾
2 设u不为s-t路径上的点
首先明确,假如u走到了s-t路径上的一点,那么接下来的路径肯定都在s-t上了,而且终点为s或t,在1中已经证明过了
所以现在又有两种情况了:
1:u走到了s-t路径上的某点,假设为X,最后肯定走到某个端点,假设是t ,则路径总长度为dis(u,X)+dis(X,t)
2:u走到最远点的路径u-T与s-t无交点,则dis(u-T) >dis(u,X)+dis(X,t);显然,如果这个式子成立,
则dis(u,T)+dis(s,X)+dis(u,X)>dis(s,X)+dis(X,t)=dis(s,t)最长路不是s-t矛盾
附上一张第二种情况的图
这道题让你求出距离每个点最远的点之间距离是多少,因为每个点走的最长路的重点肯定是直径上的某个端点,所以,写个bfs不断的搜吧
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<vector>
#define N 30005
#define in push_back
using namespace std;
vector<int>e[N];
vector<int>d[N];
int k,u,v,w,n,t;
int d1[N],d2[N];
bool b[N];
void bfs(int s,int &t,int w[])
{
queue<int>q;int mx=0;
memset(b,0,sizeof(b));
memset(w,0,sizeof(w));
q.push(s);b[s]=1;w[s]=0;
while(!q.empty())
{
int now=q.front();q.pop();
for(int i=0;i<e[now].size();i++)
{
v=e[now][i];if(b[v])continue;
{
w[v]=w[now]+d[now][i];
b[v]=1;q.push(v);
if(w[v]>mx) mx=w[v],t=v;
}
}
}
}
int main()
{
scanf("%d",&t);
k=0;
while(t--)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{e[i].clear();d[i].clear();}
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&u,&v,&w);
e[u].in(v);e[v].in(u);
d[u].in(w);d[v].in(w);
}
memset(d1,0,sizeof(d1));
memset(d2,0,sizeof(d2));
int x,y;
bfs(0,x,d1);
bfs(x,y,d1);
bfs(y,x,d2);
printf("Case %d:\n",++k);
for(int i=0;i<n;i++)
{
printf("%d\n",max(d1[i],d2[i]));
}
}
}
代码来自某大神~~~~
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
struct edge
{
int v;
int w;
int next;
}edge[60010];
int head[30005];
int tot = 1;
void add(int u,int v,int w)
{
edge[tot].v=v;
edge[tot].next=head[u];
edge[tot].w=w;
head[u]=tot++;
}
int t,n,u,v,w;
int vis[30005];
int l1[30004],l2[30005];
long long cost1[30004],cost2[30004];
int num[30004];
void dfs(int u,int p)
{
l1[u]=0;
l2[u]=0;
cost1[u]=0;
cost2[u]=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
int w = edge[i].w;
if(v==p) continue;
dfs(v,u);
if(cost2[u]<cost1[v]+w)
{
cost2[u]=cost1[v]+w;
if(cost1[u]<cost2[u])
{
// swap(l1[u],l2[u]);
swap(cost1[u],cost2[u]);
num[u]=v;
}
}
}
}
void dfs2(int u,int p)
{
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
int w = edge[i].w;
if(v==p) continue;
if(v==num[u])
{
if(cost2[v]<cost2[u]+w)
{
cost2[v]=cost2[u]+w;
if(cost1[v]<cost2[v])
{
// swap(l1[v],l2[v]);
swap(cost1[v],cost2[v]);
num[v]=u;
}
}
}
else
{
if(cost2[v]<cost1[u]+w)
{
// l2[v]=l1[u]+1;
cost2[v]=cost1[u]+w;
if(cost1[v]<cost2[v])
{
//swap(l1[v],l2[v]);
swap(cost1[v],cost2[v]);
num[v]=u;
}
}
}
dfs2(v,u);
}
}
int main()
{
scanf("%d",&t);
int Case = 1;
while(t--)
{
scanf("%d",&n);
tot=1;
memset(head,-1,sizeof(head));
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
dfs(0,-1);
dfs2(0,-1);
printf("Case %d:\n",Case++);
for(int i=0;i<n;i++)
{ //printf("%d %lld %lld \n",i,cost1[i],cost2[i]);
printf("%lld\n",cost1[i]);
}
}
return 0;
}