【算法導論】22.2-7 樹的直徑問題

樹的直徑是指樹的最長簡單路。求法: 兩遍BFS :先任選一個起點BFS找到最長路的終點,再從終點進行BFS,則第二次BFS找到的最長路即爲樹的直徑;
原理: 設起點爲u,第一次BFS找到的終點v一定是樹的直徑的一個端點
證明: 1) 如果u 是直徑上的點,則v顯然是直徑的終點(因爲如果v不是的話,則必定存在另一個點w使得u到w的距離更長,則於BFS找到了v矛盾)
         2) 如果u不是直徑上的點,則u到v必然於樹的直徑相交(反證),那麼交點到v 必然就是直徑的後半段了

         所以v一定是直徑的一個端點,所以從v進行BFS得到的一定是直徑長度

代碼如下:

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

#define  N 7
#define INFINITE 0x7fffffff
#define WHITE 1
#define GRAY 2
#define BLACK 3

//頂點結點結構  
struct Vertex  
{  
	Vertex * next;/*指向下一個頂點*/
	int id;/*節點的標誌*/
    int color;//顏色  
    Vertex *p;//指向遍歷結果的父結點  
    int d;//與源點之間的距離  
    Vertex():next(NULL),id(0),color(WHITE),p(NULL),d(INFINITE){}  
};  

//圖結構
struct Graph
{
	Vertex *Adj[N+1];//N個頂點
	Graph()
	{ 
        for(int i = 1; i <= N; i++)  
            Adj[i] = new Vertex;  
	}
	~Graph()  
    {  
        for(int i = 1; i <= N; i++)  
            delete Adj[i];  
    }  
};
std::queue<int>Q;/*隊列,保存搜索過程的中間數據*/
int c_node;/*當前遍歷的節點*/
void Print(Graph *g);
bool Init(Graph *g);
bool InsertEdge(Graph *g , int start,int end);
void PaintColor(Graph *g,int vertex,int color);

//插入邊
bool InsertEdge(Graph *g , int start,int end)
{
	Vertex* v = new Vertex();
	v->id = end;
	if(g->Adj[start]->next == NULL)
	{/*如果不存在臨界表的頭結點列表中,則插入*/
		Vertex* s = new Vertex();
		s->id = start;
		g->Adj[start] = s;
	}
	Vertex* tmp = g->Adj[start];
	while(tmp->next)
	{
		tmp = tmp->next;
	}
	tmp->next =v;
	return true;
}

/*初始化鄰接表表示樹,無向圖。
		 1
		/ \
	   2   3
	  /\   /\
	 4 5  6  7
*/
bool Init(Graph *g)
{
	InsertEdge(g,1,2);
	InsertEdge(g,2,1);
	InsertEdge(g,1,3);
	InsertEdge(g,3,1);
	InsertEdge(g,2,4);
	InsertEdge(g,4,2);
	InsertEdge(g,2,5);
	InsertEdge(g,5,2);
	InsertEdge(g,3,6);
	InsertEdge(g,6,3);
	InsertEdge(g,3,7);
	InsertEdge(g,7,3);

	return true;
}
/*
	寬度優先搜索,vertex爲初試的節點
	這種方法適合於無向圖,如果是有向圖會產生死循環
*/
bool BreadFirstSearch(Graph *g,int vertex)
{
	 //對所有結點進行初始化    
    for(int i = 1; i <= N; i++)    
    {    
        //g->Adj[i]->color = WHITE;    
        g->Adj[i]->d = INFINITE;    
        g->Adj[i]->p = NULL;    
		PaintColor(g,i,WHITE);
    } 
	PaintColor(g,vertex,GRAY);
    g->Adj[vertex]->d = 0;  
    g->Adj[vertex]->p = NULL;  
    while(!Q.empty())  
    {  
        Q.pop();
    }  
	Q.push(vertex);
    while(!Q.empty())  
    {  /*應該存儲節點的ID,不應該是數據結構,可以節省存儲空間*/
        int node = Q.front();
		c_node = node;
		Vertex *v = g->Adj[node]; //Q.front();  
        Q.pop();  
        std::cout<<v->id<<"\t";  
		while(v)
		{
			if(v->color == WHITE)
			{
				PaintColor(g,v->id,GRAY);
				g->Adj[v->id]->d = g->Adj[node]->d +1;
				Q.push(v->id);
			}
			v = v->next;
		}
		PaintColor(g,node,BLACK);
    }  
    return true;  
}
/*
	對臨界表的節點染色
*/
void PaintColor(Graph *g,int vertex,int color)
{
	g->Adj[vertex]->color = color;
	for(int i=1;i<=N;i++)
	{
		Vertex *v = g->Adj[i];
		v = v->next;
		while(v)
		{
			if(v->id == vertex)
			{
				v->color = color;
			}
			v = v->next;
		}
	}
}
/*
顯示結果
1       2       3       4       5       6       7
7       3       1       6       2       4       5
4
*/
int main(int argc,char *argv[])
{
	//構造一個空的圖
	Graph *g = new Graph;
	Init(g);
	BreadFirstSearch(g,1);
	std::cout<<std::endl;
	BreadFirstSearch(g,c_node);
	std::cout<<std::endl;
	/*最後的節點的深度即樹的最大直徑*/
	std::cout<<g->Adj[c_node]->d<<std::endl;
	getchar();
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章