【演算法導論】24.1 Bellman-Ford 演算法

李亞超發表於2012-11-19

本程式碼為演算法導論24.1的C++實現。

#include <iostream>
using namespace std;

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

//頂點結點結構  
struct Vertex  
{  
	Vertex * next;/*指向下一個頂點*/
	int id;/*節點的標誌*/
	int weight;/*節點的權值,臨界表表頭到此元素上邊的權值*/
    Vertex():next(NULL),id(0){}  
};  

//圖結構
struct Graph
{
	Vertex *Adj[N+1];//N個頂點及鄰接點頭指標
	int p[N+1];//指向遍歷樹節點的父結點 
	int d[N+1];/*節點的最短路徑權值的上界*/
	Graph()
	{ 
        for(int i = 1; i <= N; i++)  
		{
            Adj[i] = new Vertex;
			d[i] = 0;
			p[i] = 0;
		}
	}
	~Graph()  
    {  
        for(int i = 1; i <= N; i++)  
            delete Adj[i];  
    }  
};

void Print(Graph *g);
bool Init(Graph *g);
bool InsertEdge(Graph *g , int start,int end,int weight);
bool InitializeSingleSource(Graph *g,int s);
bool Relax(Graph *g,int u,int v,int weight);
bool Relax(Graph *g,int u,int v);
int  Weight(const Graph *g,int u,int v);

/*
start邊開始節點,end邊結束節點,weight邊權值
*/
//插入邊
bool InsertEdge(Graph *g , int start,int end,int weight)
{
	Vertex* v = new Vertex();
	v->id = end;
	v->weight = weight;
	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;
}

/*初始化臨接表表示的圖,有向圖。
*/
bool Init(Graph *g)
{
	InsertEdge(g,1,2,6);
	InsertEdge(g,1,4,7);
	InsertEdge(g,2,3,5);
	InsertEdge(g,2,4,8);
	InsertEdge(g,2,5,-4);
	InsertEdge(g,3,2,-2);
	InsertEdge(g,4,3,-3);
	InsertEdge(g,4,5,9);
	InsertEdge(g,5,1,2);
	InsertEdge(g,5,3,7);
	return true;
}

/*取得兩個兩個節點連線的邊的權重*/
int Weight(const Graph *g,int u,int v)
{
	Vertex * t = g->Adj[u]->next;
	while(t)
	{
		if(t->id == v)
		{
			return t->weight;
		}
		t = t->next;
	}
	return 0;
}
bool Relax(Graph *g,int u,int v,int weight)
{
	if(g->d[v] > (g->d[u] + Weight(g,u,v)))
	{
		g->d[v] = g->d[u] + Weight(g,u,v);
		g->p[v] = u;
	}
	return true;
}
/*對邊進行鬆弛操作*/
bool Relax(Graph *g,int u,int v)
{
	Relax(g,u,v,Weight(g,u,v));
	return false;
}
/*
最短路徑估計和前驅化進行初始化
s 源頂點
*/
bool InitializeSingleSource(Graph *g,int s)
{
	for(int i=1;i<=N;i++)
	{
		g->d[i] = INFINITE;
		g->p[i] = 0;
	}
	g->d[s] = 0;
	return true;
}
/*單源最短路徑的Bellman-Ford演算法*/
bool BellmanFord(Graph *g,int s)
{
	InitializeSingleSource(g,s);
	for(int i=1;i<N;i++)
	{/*對每個邊進行N-1次鬆弛操作*/
		for(int j=1;j<=N;j++)
		{
			Vertex * t = g->Adj[j]->next;
			while(t)
			{
				Relax(g,j,t->id);
				t = t->next;
			}
		}
	}
	for(int i=1;i<=N;i++)
	{/*如果包含從原點可達的負權迴路,返回FALSE*/
		Vertex * t = g->Adj[i]->next;
		while(t)
		{
			if(g->d[t->id] > (g->d[i] + Weight(g,i,t->id)))
			{
				return false;
			}
			t = t->next;
		}
	}
	return true;
}
/*
開始頂點 1
頂點  最短路徑
1       0
2       2
3       4
4       7
5       -2
*/
int main(int argc,char * argv[])
{
	//構造一個空的圖
	Graph *g = new Graph;
	Init(g);
	BellmanFord(g,1);
	for(int i=1;i<=N;i++)
	{
		std::cout<<i<<"\t"<<g->d[i]<<std::endl;
	}
	delete g;
	getchar();
	return 0;
}


相關文章