樹的直徑:一棵樹中從一個節點到另一個節點的一條最長的路徑,這條路徑可以只是這個樹上的部分節點,也可以是所有節點(主要看這棵樹的連接方式)在這個路徑上任意節點的分岔不予考慮
求法:先任意選擇一個節點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; }