1. 程式人生 > >Dijastra最優路徑演算法

Dijastra最優路徑演算法

關於Dijastra演算法,零零散散地研究了差不多兩天了,基本上弄懂了它的思路和寫程式的思路。演算法思路不是很難(沒理解時還是覺得有點晦澀),程式碼的實現過程,需要反覆推敲和琢磨。目前先寫個初級版本(現在暫時只理解到這個程度)

演算法的思想和方法,各路牛人已經寫過很多,小菜鳥就不贅述了,對我自己而言,我覺得下面的思路有助於我的理解,寫上來:

首先上一個無向圖,以及對應的Dijastra演算法過程(來源http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html我在理解時,也參考了這篇文章)



大致思路,首先選取源結點A,將除源節點以外的其他結點分到U集合中,然後從A開始,遍歷與它直接相鄰的結點,選取路徑AC最短,故C結點做為下一次的起始點。上面的表,對於這個過程描述得很清楚。看完這個,演算法的思想大致就理解了。但是對於程式碼,還是有一定距離的。下面是我手寫的,對於這個演算法,程式碼大致的思路



完整程式碼C++實現:

<pre name="code" class="cpp">#include<iostream>
#include<iomanip>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <list>
#include<vector>

using namespace std;

const int MAX_required = 505;//城市數量最大值
const int Max_int = 0x7fffffff;//城市間沒有路徑時,將距離設定為一個很大的數
int map[MAX_required][MAX_required];//用陣列存放城市地圖
int callnum[MAX_required];//該陣列存放每個城市對應救援團隊的數量

struct  CITY
{
	int dist; //該結點至源節點的最短距離
	bool visited;//是否被訪問過
	int number;//最短路徑數量,這裡是為了AdvancePAT 1003那道題設定的,可以不用
	int call;//每個城市對應的救援團隊數量
	int prev;//從源點到這個點的最短路徑中,該點的前一個結點

}city[MAX_required];//新建陣列,存放型別為CITY

void Dijkstra(int start, int end,int n)
{	
	/*int callnum[6] = { 3, 2, 1, 3, 3, 4 };
	int map[6][6] = {
		{ Max_int, 7, 9, Max_int, Max_int, 14 },
		{ 7, Max_int, 10, 15, Max_int, Max_int },
		{ 9, 10, Max_int, 11, Max_int, 2 },
		{ Max_int, 15, 11, Max_int, 6, Max_int },
		{ Max_int, Max_int, Max_int, 6, Max_int, 9 },
		{ 14, Max_int, 2, Max_int, 9, Max_int }
	};*///測試使用程式碼,可以忽略
	
	
	for (int i = 0; i < n; i++)//初始化所有的項
	{
		city[i].dist = Max_int;
		city[i].visited = 0;
		city[i].number = 0;
		city[i].call = 0;
		city[i].prev = 0;//這裡初值是否該為0
	}

	city[start].dist = 0;//初始化源點到自己的距離為0
	city[start].number = 1;//如果不是做PAT題,該變數不需要
	city[start].call = callnum[start];//如果不是做PAT題,該變數不需要

	//求最短路徑及其位置
	for (int cnt = 0; cnt < n; cnt++)//控制總共迴圈的次數
	{
		int Min = Max_int, pos = -1;//min記錄最小路徑,pos記錄下一個訪問結點的標記

		//找到最短距離,以及對應下標,作為下一次的起始節點
		for (int i = 0; i < n; i++)
		{
			if ((city[i].visited == 0) && (city[i].dist < Min))
			{
				Min = city[i].dist;
				pos = i;							
			}
		}

		if (pos == -1)
			break;

		city[pos].visited = 1;

		//根據下一個結點在矩陣中對應的值,調整結點到原點距離的最小值和對應的救援團隊數量
		for (int j = 0; j < n; j++)
		{
			if ((city[j].visited == 0) && (map[pos][j] != Max_int))//注意這裡要判斷map中對應的值是否為無窮大,即沒有路徑
			{
				if (city[j].dist>city[pos].dist + map[pos][j])
				{
					city[j].dist = city[pos].dist + map[pos][j];
					city[j].number = city[pos].number;
					city[j].call = city[pos].call+callnum[j];
					city[j].prev = pos;
				}
				/*else if (city[j].dist==(city[pos].dist + map[pos][j]))//這種情況是為了處理最短路徑有多條時的情況
				{
					city[j].number += city[pos].number;
					if (city[j].call < city[pos].call + callnum[j])
						city[j].call = city[pos].call + callnum[j];
				}*/
			}
		}
	}

	cout << "結點" << start << "到結點" << end << "的最短距離為" << city[end].dist;

	vector<int> final_path;
	final_path.push_back(end);//通過前驅結點,將end到start的最短路徑找出來,放在容器中
	int temp = city[end].prev;
	while (temp != start)
	{		
		final_path.push_back(temp);
		temp = city[temp].prev;
	}	
	final_path.push_back(start);

	cout << "路徑為";
	for (int i = final_path.size() - 1; i >= 0; i--)
	{
		if (i)
		{
			cout << final_path[i] << "->";
		}
		else
		{
			cout << final_path[i];
		}
	}
	cout << city[end].dist << " " << city[end].call;//這個是為了配合PAT1003那道題的,單純的Dijkstra演算法求最短路徑及相應的值已經搞定
}

int main()
{
		int n, m, start, end;	//分別表示城市數量,道路數量,起始城市和終點城市
		cin >> n >> m >> start >> end;
		int i;
		for (i = 0; i<n; i++)//輸入每個城市救援隊數目,不做PAT請忽略這裡
			cin >> callnum[i];
		int a, b, l;	
		for (int i = 0; i < n; i++)//初始化map中城市間是沒有道路的
		{
			for (int j = 0; j < n; j++)
			{
				map[i][j] = Max_int;
			}
		}
		for (i = 0; i<m; i++)//輸入城市間距離
		{
			cin >> a >> b >> l;
			map[a][b] = l;
			map[b][a] = l;
		}		

		//輸入樣例
		/*5 6 0 2
		1 2 1 5 3
		0 1 1
		0 2 2
		0 3 1
		1 2 1
		2 4 1
		3 4 1*/

		//////除錯使用,可以不適用輸入樣例,直接用這部分除錯程式碼。注意將int callnum[6]以後的程式碼寫在Dijkstra函式中
		//int n = 6, m = 9;
		//int start = 0, end = 4;
		//cin >> start >> end;
		//int callnum[6] = { 3, 2, 1, 3, 3, 4 };
		//int map[6][6] = {
		//	{ Max_int, 7, 9, Max_int, Max_int, 14 },
		//	{ 7, Max_int, 10, 15, Max_int, Max_int },
		//	{ 9, 10, Max_int, 11, Max_int, 2 },
		//	{ Max_int, 15, 11, Max_int, 6, Max_int },
		//	{ Max_int, Max_int, Max_int, 6, Max_int, 9 },
		//	{ 14, Max_int, 2, Max_int, 9, Max_int }
		//};//發現這部分程式碼如果寫在主函式裡,到呼叫Dijkstra時,map中元素全部為0,還沒太弄明白

		Dijkstra(start, end, n);

		return 0;
}