學弟講算法·SPFA求最短路

一、實驗目的

通過SFPA算法求出某個點到其餘點的最短路徑

二、實驗環境

gcc 4.9.2

三、實驗過程

3.1 理論方法

  1. 建立一個隊列,存入開始節點

  2. 隊列不爲空時:

    取出隊頭節點X,X出隊
    遍歷與X節點相通的節點Y,若X到Y的距離可縮小(鬆弛),且Y不在隊列中
    則將Y入隊,繼續操作2

爲求A點到其餘節點的最短路.設定 p[i]爲A到i節點的路徑


初始狀態,建立點A到其餘各點的最短路徑

A B C D E
p[i] 0

點A進入隊列,若隊列非空時:

隊頭點A出隊,對以A爲起點的所有邊的終點進行鬆弛操作(涉及點B,E)

A B C D E
p[i] 0 13 70

點B,E的最短路徑變小,且點B,E未在隊列中,故點B,E入隊,隊列中結點爲B,E

隊頭點B出隊,對以B爲起點的所有邊的終點進行鬆弛操作(涉及點C,D)

A B C D E
p[i] 0 13 41 17 70

點C,D的最短路徑變小,且點C,D未在隊列中,故點C,D入隊,隊列中結點爲E,C,D


隊頭元素E出隊,對以E爲起點的所有邊的終點進行鬆弛操作

隊頭元素C出隊,對以C爲起點的所有邊的終點進行鬆弛操作(D,E)

A B C D E
p[i] 0 13 41 17 56

點E的最短路徑改變了,且點E未在隊列中,故點E入隊,隊列中結點爲D,E

隊頭元素D出隊,對以D爲起點的所有邊的終點進行鬆弛操作

隊頭元素E出隊,對以E爲起點的所有邊的終點進行鬆弛操作

隊列爲空,結束

點A到其他點的最短路徑爲

A B C D E
p[i] 0 13 41 17 56

3.2 代碼實現

數據定義

//記錄邊的起點、終點、兩點間權值
typedef struct E {
	//起點
	char sp;
	//終點
	char ep;
	//權值
	int w;
	E() {}
	E(char s, char e, int w) : sp(s), ep(e), w(w) {}
} E;

//保存邊
vector<E> edge;

char node[5] = {'A','B','C','D','E'};

//記錄點s到其他點最短路
int path[SIZE];

//記錄點是否在隊列
int in[SIZE];
//獲取節點下標
int getIndex(char n) {
	for(int i = 0 ; i<5; i++) {
		if(node[i] == n) {
			return i;
		}
	}
}

//求s到其他點間的最短路
void SPFA(char s) {
	queue<char> q;
	//開始時將點s到其他點的距離設爲∞
	memset(path, MAXV, sizeof(path));
	memset(in, 0, sizeof(in));
	int index = getIndex(s);
	//點s自己到自己的最短路爲0
	path[index] = 0;
	q.push(s);
	in[index] = 1;
	while (!q.empty()) {
		char x = q.front();
		int x_index = getIndex(x);
		q.pop();
		in[x_index] = 0;
		//遍歷所有與x所連通的節點,進行鬆弛操作
		for (int i = 0; i < edge.size(); i++) {
			//若某個邊的起點是x
			if (edge[i].sp == x) {
				//cout<<edge[i].sp<<" "<<edge[i].ep<<endl;
				//獲取該邊的終點
				char end = edge[i].ep;
				int end_index = getIndex(end);
				//若從點S經過點X到點end的距離比S直接到end的距離短,則可進行鬆弛操作
				if (path[x_index] + edge[i].w < path[end_index]) {
					//從點S到點end的距離更新爲點S到X的距離與X到end的距離之和
					path[end_index] = edge[i].w + path[x_index];
					//cout<<"path["<<end<<"] = "<<path[end_index]<<endl;
					if (!in[end_index]) {
						q.push(end);
						in[end_index] = 1;
					}
				}
			}
		}
	}
}

四、完整測試代碼

#include <cstring>
#include <iostream>
#include <queue>
#include <vector>
const int SIZE = 5;
const int MAXV = 10000; 
using namespace std;

typedef struct E {
	char sp;char ep;int w;
	E() {}
	E(char s, char e, int w) : sp(s), ep(e), w(w) {}
} E;

vector<E> edge;

char node[5] = {'A','B','C','D','E'};

int path[SIZE];

int in[SIZE];

int getIndex(char n) {
	for(int i = 0 ; i<5; i++) {
		if(node[i] == n) {
			return i;
		}
	}
}

//求s到其他點間的最短路
void SPFA(char s) {
	queue<char> q;
	memset(path, MAXV, sizeof(path));
	memset(in, 0, sizeof(in));
	int index = getIndex(s);
	path[index] = 0;
	q.push(s);
	in[index] = 1;
	while (!q.empty()) {
		char x = q.front();
		int x_index = getIndex(x);
		q.pop();
		in[x_index] = 0;
		for (int i = 0; i < edge.size(); i++) {
			//若某個邊的起點是x
			if (edge[i].sp == x) {
				//獲取該邊的終點
				char end = edge[i].ep;
				int end_index = getIndex(end);
				if (path[x_index] + edge[i].w < path[end_index]) {
					path[end_index] = edge[i].w + path[x_index];
					if (!in[end_index]) {
						q.push(end);
						in[end_index] = 1;
					}
				}
			}
		}
	}
}

//建立測試數據
void init() {
	E e[6];
	e[0] = E('A','B',13);
	e[1] = E('A','E',70);
	e[2] = E('B','D',4);
	e[3] = E('B','C',28);
	e[4] = E('C','D',23);
	e[5] = E('C','E',15);
	for(int i = 0 ; i< 6; i++) {
		edge.push_back(e[i]);
	}
}

int main() {
	init();
	char s = 'A';
	SPFA(s);
	for(int i = 0 ; i<5;i++){
		cout<<"p["<<node[i]<<"] = "<<path[i]<<endl;
	}
	return 0;
}

運行結果

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