樹的直徑:一棵樹中從一個節點到另一個節點的一條最長的路徑,這條路徑可以只是這個樹上的部分節點,也可以是所有節點(主要看這棵樹的連接方式)在這個路徑上任意節點的分岔不予考慮
求法:先任意選擇一個節點a當做起點來找到距離這個點最遠的端點b(這兩點之間的路徑上所有邊的權值和最大),然后再以b節點為起點找到距離b點最遠的節點c此時b點到c點的距離就是這棵樹上路徑最長的距離。
實現:因為求樹的直徑題目數據量往往比較大,所以用鄰接表來儲存數據;至於對兩個端點的查找通過bfs實現,先將第一次選擇的起點a隊然后開始搜索與a連接的所有邊,並將權值存入dis[]數組 dis[x]=dis[top]+edge[i].w(dis[x]指的是當前搜索到的點與之前與它相 連的搜索過邊的總權值,dis[top]是指當前搜索到的點的之前與它相連的搜索過邊的總權值,edge[i].w是點top到當前搜索到的點 的連線的權值)完成於對當前點的搜索后,將其入隊,然后對下一個點進行此操作,每次搜索時,同時將最大的權值存入sum中如此重復直至隊列為空,這樣這個搜素結束后,sum的值就是a點到距離其最遠的點b的總權值之和;此時再以b為起點進行第二次搜索(第 二次搜 索步驟與第一次相同)
#include<stdio.h>
#include<string.h>
#include<queue>
#define MAX 100000
using namespace std;
int head[MAX];
int vis[MAX];//標記當前節點是否已經用過
int dis[MAX];//記錄最長距離
int n,m,ans;
int sum;//記錄最長路徑的長度
int aga;
struct node
{
int u,v,w;
int next;
}edge[MAX];
void add(int u,int v,int w)//向鄰接表中加邊
{
edge[ans].u=u;
edge[ans].v=v;
edge[ans].w=w;
edge[ans].next=head[u];
head[u]=ans++;
}
void getmap()
{
int i,j;
int a,b,c;
ans=0;
memset(head,-1,sizeof(head));
while(m--)
{
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b,a,c);
}
}
void bfs(int beg)
{
queue<int>q;
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));
int i,j;
while(!q.empty())
q.pop();
aga=beg;
sum=0;
vis[beg]=1;
q.push(beg);
int top;
while(!q.empty())
{
top=q.front();
q.pop();
for(i=head[top];i!=-1;i=edge[i].next)
{
if(!vis[edge[i].v])
{
dis[edge[i].v]=dis[top]+edge[i].w;
vis[edge[i].v]=1;
q.push(edge[i].v);
if(sum<dis[edge[i].v])
{
sum=dis[edge[i].v];
aga=edge[i].v;
}
}
}
}
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
getmap();
bfs(1);//搜索最長路徑的一個端點
bfs(aga);//搜索另一個端點
printf("%d\n",sum);
}
return 0;
}
