一、實驗目的
通過SFPA算法求出某個點到其餘點的最短路徑
二、實驗環境
gcc 4.9.2
三、實驗過程
3.1 理論方法
-
建立一個隊列,存入開始節點
-
隊列不爲空時:
取出隊頭節點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;
}
運行結果