一、題目
樹T=(V,E)的直徑(diameter)定義為max(u,v),亦即,樹的直徑是樹中所有最短路徑長度中的最大值。試寫出計算樹的直徑的有效演算法,並分析演算法的已耗用時間。
二、思考
step1:以樹中任意一個結點為源點,進行一次廣度優先遍曆,找出離源點距離最遠的點d
step2:以d為源點,進行一次廣度優先遍曆,找出離d最遠的點,並記錄其長度
三、代碼
//用鄰接表實現圖的轉置#include <iostream>#include <queue>using namespace std;#define N 8#define WHITE 0#define GRAY 1//邊結點結構struct Edge{int start;//有向圖的起點int end;//有向圖的終點Edge *next;//指向同一個起點的下一條邊Edge(int s, int e):start(s),end(e),next(NULL){}};//頂點結點結構struct Vertex{Edge *head;//指向以該頂點為起點的下一條邊bool color;//顏色,我覺得兩種顏色就夠了Vertex *p;//指向遍曆結果的父結點int d;//與源點之間的距離Vertex():head(NULL),color(WHITE),p(NULL),d(0x7fffffff){}};//圖結構struct Graph{Vertex *V[N+1];//N個頂點Graph(){int i;for(i = 1; i <= N; i++)V[i] = new Vertex;}~Graph(){int i;for(i = 1; i <= N; i++)delete V[i];}};//廣搜的先進先出用STL中的隊列來實現queue<Vertex*> Q;//插入邊void InsertEdge(Graph *G, Edge *E){//如果沒有相同起點的邊if(G->V[E->start]->head == NULL)G->V[E->start]->head =E;//如果有,加入到鏈表中,遞增順序排列,便於查重else{//鏈表的插入,不解釋Edge *e1 = G->V[E->start]->head, *e2 = e1;while(e1 && e1->end < E->end){e2 = e1;e1 = e1->next;}if(e1 && e1->end == E->end)return;if(e1 == e2){E->next = e1;G->V[E->start]->head =E;}else{e2->next = E;E->next = e1;}}}//在廣度優先搜尋的同時,記錄從離源點最遠的點及其長度void BFS(Graph *G, Vertex *s, int &ls, int &lv){int i;//雖然所有結點在建構函式中初始化過了,但是如果對同一圖多次搜尋,每次都要重新初始化for(i = 1; i <= N; i++){G->V[i]->color = WHITE;G->V[i]->d = 0x7fffffff;G->V[i]->p = NULL;}//對s進行特殊的初始化s->color = GRAY;s->d = 0;s->p = NULL;//初始化隊列,使其僅含源頂點swhile(!Q.empty())Q.pop();Q.push(s);//只要隊列中還有灰色頂點,迴圈將一直進行下去while(!Q.empty()){//確定隊列頭部的灰色頂點u,將其從隊列中去掉Vertex *u = Q.front();Q.pop();//考察u的鄰接表中每條邊的終點vEdge *e = u->head;while(e){Vertex *v = G->V[e->end];//如果v是白色的,表明該頂點尚未被發現if(v->color == WHITE){//置為灰色v->color = GRAY;//計算距離v->d = u->d + 1;if(v->d > ls){ls = v->d;lv = v->id;}//u被標記為該頂點的父母v->p = u;//將它置於隊列的尾部Q.push(v);}e = e->next;}//當u的鄰接表中的所有頂點被檢查完後,u被置為黑色(僅僅是便於理解,沒有實際意義)u->color = GRAY;}}//輸出void Print(Graph *G){int i;//遍曆每個頂點for(i = 1; i <= N; i++){cout<<i<<':';//輸出以i為起點的邊的終點Edge *e = G->V[i]->head;while(e){cout<<e->end<<' ';e = e->next;}cout<<endl;}cout<<endl;}/*1 21 44 22 55 43 63 56 6*//*1 21 52 66 37 63 73 44 87 87 4*/int main(){//構造一個空的圖Graph *G = new Graph;Edge *E;Print(G);//輸入邊int i, start, end;for(i = 1; i <= 10; i++){cin>>start>>end;E = new Edge(start, end);InsertEdge(G, E);//無向圖,要加兩條邊E = new Edge(end, start);InsertEdge(G, E);}Print(G);int ls = -1, lv;//第一次搜尋,從任意結點出發,找出最遠的點lv,lv一定是所求路徑上的一個端點BFS(G, G->V[1], ls, lv);ls = -1;//第二次搜尋,從lv出發,找出最長的路徑BFS(G, G->V[lv], ls, lv);cout<<ls<<endl;return 0;}