算法筆記---Dijkstra算法

Dijkstra算法(讀者可以將其讀作“迪傑斯特拉算法”)用來解決單源最短路問題,給定圖G和起點s,通過算法得到S到達其他每個頂點的最短距離。
算法基本思想:
1、對圖G(V,E)設置集合S,存放已被訪問的頂點。
2、每次從集合V-S中選擇與起點s的最短距離最小的一個頂點(記爲u),訪問並加入集合S。
3、令頂點u爲中介點,優化起點s與所有從u能到達的頂點v之間的最短距離。
4、這樣的操作執行n次(n爲頂點個數),直到集合S已包含所有頂點。

題目描述

圖片來自於算法筆記

在這裏插入圖片描述
樣例:

輸入:
6 8 0//6個頂點,8條邊,起點爲0號。以下8行爲8條邊
0 1 1//邊0->1的邊權爲1,下同
0 3 4
0 4 4
1 3 2
2 5 1
3 2 2
3 4 3
4 5 3
輸出:
0 1 5 3 4 6

運行結果:

在這裏插入圖片描述

書中給出兩種解決方法:
1、使用鄰接矩陣來存儲圖的信息
2、使用鄰接表來存儲圖的信息
上邊兩種算法只是在尋找最短路徑的時候不同,其他的都相同

實際上,使用 stl 庫中的priority_queue可以更快的求解,且時間複雜度爲O(V*logV+E)

下面爲代碼:

#include<iostream>
#include<queue>
#include<vector>
#include<map>
#include<algorithm>
#include<limits.h>
#include<stack>
using namespace std;

const int dij_max_v = 101;

struct DijNode
{
	int id;//當前結點id
	int weight;//到該結點的權值
};

struct MinWeightCompare//小頂堆
{
	bool operator() (const DijNode node1, const DijNode node2) const{
		return node1.weight > node2.weight;
	}
};


//************************************
// Method:    dijkstra 返回單源最短路徑
// FullName:  dijkstra
// Access:    public 
// Returns:   void
// Qualifier:
// Parameter: vector<DijNode> matrix[] 給定的圖
// Parameter: DijNode start 初始結點
// Parameter: bool * visited 表示當前結點是否被訪問
// Parameter: map<int,int> & parent 表示當前到結點的上一個結點
// Parameter: map<int,int> & distance 表示初始結點到當前結點的最短路徑
//************************************
void dijkstra(vector<DijNode> matrix[], DijNode start, bool* visited, map<int, int>& parent, map<int, int>& distance) {
	priority_queue<DijNode, vector<DijNode>, MinWeightCompare> p_queue;//BFS 隊列
	//該優先隊列中的元素表示到當前結點的最短路徑。
	p_queue.push(start);

	while (!p_queue.empty())
	{
		DijNode top_node = p_queue.top();
		p_queue.pop();
		visited[top_node.id] = true;//標記當前結點已被訪問
		for (int i = 0;i < matrix[top_node.id].size();i++)
		{
			DijNode next_node = matrix[top_node.id][i];
			//當前結點沒有被訪問,且以 top_node 爲中介點可以使得 next_node 更優
			if (visited[next_node.id] == false && distance[top_node.id] + next_node.weight < distance[next_node.id])
			{
				distance[next_node.id] = distance[top_node.id] + next_node.weight;
				DijNode node;
				node.id = next_node.id;
				node.weight = distance[next_node.id];//更新當前的最短距離
				p_queue.push(node);//將所遍歷的結點加入到隊列中
				parent[next_node.id] = top_node.id;//更新所遍歷結點的父結點
			}
		}
	}
}

//打印start_node 到 end_node 的最短路徑所經過的結點
void print_path(int start_node, int end_node, map<int, int>& parent) {
	stack<int> s;
	while (start_node != end_node)
	{
		s.push(end_node);
		end_node = parent[end_node];
	}
	while (!s.empty())
	{
		int result = s.top();
		s.pop();
		cout << result << " ";
	}
}


int main() {

	int n, m, s;//表示頂點個數,邊數,初始結點
	cin >> n >> m >> s;
	int form_node, to_node, weight;//表示起始結點,終止結點,權值
	vector<DijNode> matrix[dij_max_v];//用來存放圖
	DijNode node;

	map<int, int> parent;//存放當前結點的路徑的上一個結點
	parent[s] = -1;//起始結點的父結點爲 -1

	map<int, int> distance;//記錄起始結點到其他結點的最短路徑
	distance[s] = 0;//自己到自己的距離爲 0 
	for (int i = 0;i < m;i++)
	{
		cin >> form_node >> to_node >> weight;
		node.id = to_node;
		node.weight = weight;
		matrix[form_node].push_back(node);
		if (to_node != s)
		{
			distance[to_node] = INT_MAX;//表示除了起始結點,剩下的皆爲不可達
		}
	}
	
	bool visited[dij_max_v];
	fill(visited, visited + dij_max_v, false);
	node.id = s;//起始結點的id
	node.weight = 0;//起始結點距離自己的距離
	dijkstra(matrix, node, visited, parent, distance);
	//輸出初始結點到每個結點的最短路徑
	for (map<int,int>::iterator it = distance.begin();it != distance.end();it++)
	{
		cout << (*it).second << " ";
	}
	system("pause");
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章