(最短路徑算法整理)dijkstra、floyd、bellman-ford、spfa算法模板的整理與介紹
這一篇博客以一些OJ上的題目為載體。整理一下最短路徑算法。會陸續的更新。。。
一、多源最短路算法——floyd算法
floyd算法主要用於求隨意兩點間的最短路徑。也成最短最短路徑問題。
核心代碼:
/** *floyd算法 */ void floyd() { int i, j, k; for (k = 1; k <= n; ++k) {//遍歷全部的中間點 for (i = 1; i <= n; ++i) {//遍歷全部的起點 for (j = 1; j <= n; ++j) {//遍歷全部的終點 if (e[i][j] > e[i][k] + e[k][j]) {//假設當前i-->j的距離大於i-->k--->j的距離之和 e[i][j] = e[i][k] + e[k][j];//更新從i--->j的最短路徑 } } } } }
時間復雜度:O(N^3)
不能使用的情況:邊中含有負權值
例題:
1、WIKIOI 1077 多源最短路
分析:這道題是floyd的裸題。
大家僅僅要理解了floyd的思想以後,基本非常快就能解答出來了。唯一須要註意的地方就是
這道題的map[][]矩陣中的頂點默認是從1開始。
假設頂點是從0開始算的須要做一下處理:printf("%d\n",map[a-1][b-1]);
/* * 1077.cpp * * Created on: 2014年5月23日 * Author: pc */ #include <iostream> #include <cstdio> using namespace std; const int maxn = 105; int e[maxn][maxn]; int n; const int inf = 99999999; void initial() { int i, j; for (i = 1; i <= n; ++i) { for (j = 1; j <= n; ++j) { if (i == j) { e[i][j] = 0; } else { e[i][j] = inf; } } } } /** *floyd算法 */ void floyd() { int i, j, k; for (k = 1; k <= n; ++k) {//遍歷全部的中間點 for (i = 1; i <= n; ++i) {//遍歷全部的起點 for (j = 1; j <= n; ++j) {//遍歷全部的終點 if (e[i][j] > e[i][k] + e[k][j]) {//假設當前i-->j的距離大於i-->k--->j的距離之和 e[i][j] = e[i][k] + e[k][j];//更新從i--->j的最短路徑 } } } } } int main() { while (scanf("%d", &n) != EOF) { initial(); int i, j; for (i = 1; i <= n; ++i) { for (j = 1; j <= n; ++j) { scanf("%d", &e[i][j]); } } floyd(); int q; scanf("%d", &q); while (q--) { int a, b; scanf("%d %d", &a, &b); printf("%d\n", e[a][b]); } } return 0; }
下面是自己再次做這道題的時候的代碼:
/* * WIKIOI_1077.cpp * * Created on: 2014年9月6日 * Author: pc */ #include <iostream> #include <cstdio> const int maxn = 105; const int inf = 999999; int map[maxn][maxn]; void initial(int n){ int i; int j; for(i = 0 ; i < n ; ++i){ for(j = 0 ; j < n ; ++j){ if(i == j){ map[i][j] = 0; }else{ map[i][j] = inf; } } } } void floyd(int n){ int i; int j; int k; for(k = 0 ; k < n ; ++k){//頂點從0開始算》。。 for(i = 0 ; i < n ; ++i){ for(j = 0 ; j < n ; ++j){ if(map[i][j] > map[i][k] + map[k][j]){ map[i][j] = map[i][k] + map[k][j]; } } } } } int main(){ int n; scanf("%d",&n); initial(n); int i; int j; for(i = 0 ; i < n ; ++i){ for(j = 0 ; j < n ; ++j){ int c; scanf("%d",&c); map[i][j] = c; } } floyd(n); int q; scanf("%d",&q); while(q--){ int a,b; scanf("%d %d",&a,&b); printf("%d\n",map[a-1][b-1]); } return 0; }
二、單源最短路徑算法——dijkstra
1、思想描寫敘述:當Q(一開始為全部節點的集合)非空時。不斷地將Q中的最小值u取出,然後放到S(最短路徑的節點的集合)集合中,然後遍歷全部與u鄰接的邊。假設能夠進行松弛,則對便進行對應的松弛。
。
。
2、實現
/** * 返回從v---->到target的最短路徑 */ int dijkstra(int v){ int i; for(i = 1 ; i <= n ; ++i){//初始化 s[i] = 0;//一開始。全部的點均為被訪問過 dis[i] = map[v][i]; } dis[v] = 0; s[v] = true; for(i = 1 ; i < n ; ++i){ int min = inf; int pos; int j; for(j = 1 ; j <= n ; ++j){//尋找眼下的最短路徑的最小點 if(!s[j] && dis[j] < min){ min = dis[j]; pos = j; } } s[pos] = 1; for(j = 1 ; j <= n ; j++){//遍歷u的全部的鄰接的邊 if(!s[j] && dis[j] > dis[pos] + map[pos][j]){ dis[j] = dis[pos] + map[pos][j];//對邊進行松弛 } } } return dis[target]; }
3、基本結構
int s[maxn];//用來記錄某一點是否被訪問過 int map[maxn][maxn];//地圖 int dis[maxn];//從原點到某一個點的最短距離(一開始是估算距離)
4、條件:使用dijkstra解決的題目一般有下面的特征:
給出點的數目、邊的數目、起點和終點、邊的信息(,而且邊不包括負邊權的值).求從起點到終點的最短路徑的距離
起點:用於dijkstra(int v)中的v
終點:用於return dis[target]中的target
邊的信息:用於初始化map[][]
5、算法運行過程分析
如圖:求0點到其它點的最短路徑。
(1)開始時,s1={v0},s2={v1,v2,v3,v4},v0到各點的最短路徑是{0,10,&,30,100};
(2)在還未進入s1的頂點之中。最短路徑為v1。因此s1={v0,v1},因為v1到v2有路徑,因此v0到各點的最短路徑更新為{0,10,60,30,100};
(3)在還未進入s1的頂點之中。最短路徑為v3,因此s1={v0,v1,v3},因為v3到v2、v4有路徑,因此v0到各點的最短路徑更新為{0,10,50,30,90};
(4)在還未進入s1的頂點之中。最短路徑為v2,因此s1={v0,v1,v3,v2},因為v2到v4有路徑。因此v0到各點的最短路徑更新為{0,10,50,30,60};
例題:
1、NEFU 207 最小樹
題目與分析:
這一道題。抽象一下,描寫敘述例如以下:“求從a到b的最短路徑的距離”。
floyd:解決多源最短路徑問題。求隨意兩個點之間的最短路徑。這當然也就包括了“從a到b的這樣的情況”。所以這道題也能夠使用floyd來解決
dijkstra:解決單源最短路徑問題 。最典型的就是解決“從a到b的最短路徑的距離”的這樣的問題了。
下面分別給出這兩種算法的解題方法
1)使用floyd
/* * NEFU_207.cpp * * Created on: 2014年5月27日 * Author: pc */ #include <iostream> #include <cstdio> using namespace std; const int maxn = 105; const int inf = 99999999; int e[maxn][maxn]; int n,m; void initial(){ int i; int j; for(i = 1 ; i <= n ; ++i){ for(j = 1 ; j <= n ; ++j){ if(i == j){ e[i][j] = 0; }else{ e[i][j] = inf; } } } } void floyd(){ int i; int j; int k; for(k = 1 ; k <= n ; ++k){ for(i = 1 ; i <= n ; ++i){ for(j = 1 ; j <= n ; ++j){ if(e[i][j] > e[i][k] + e[k][j]){ e[i][j] = e[i][k] + e[k][j]; } } } } } int main(){ while(scanf("%d%d",&n,&m)!=EOF){ initial(); int i; for(i = 1 ; i <= m ; ++i){ int a,b,c; scanf("%d%d%d",&a,&b,&c); e[a][b] = e[b][a] = c; } floyd(); printf("%d\n",e[1][n]); } return 0; }
2)使用dijkstra
/* * NEFU_207.cpp * * Created on: 2014年5月27日 * Author: pc */ #include <iostream> #include <cstdio> using namespace std; const int maxn = 105; const int inf = 9999999; int s[maxn];//用來記錄某一點是否被訪問過 int map[maxn][maxn];//地圖 int dis[maxn];//從原點到某一個點的最短距離(一開始是估算距離) int n; int target; /** * 返回從v---->到target的最短路徑 */ int dijkstra(int v){ int i; for(i = 1 ; i <= n ; ++i){//初始化 s[i] = 0;//一開始,全部的點均為被訪問過 dis[i] = map[v][i]; } for(i = 1 ; i < n ; ++i){ int min = inf; int pos; int j; for(j = 1 ; j <= n ; ++j){//尋找眼下的最短路徑的最小點 if(!s[j] && dis[j] < min){ min = dis[j]; pos = j; } } s[pos] = 1; for(j = 1 ; j <= n ; j++){//遍歷u的全部的鄰接的邊 if(!s[j] && dis[j] > dis[pos] + map[pos][j]){ dis[j] = dis[pos] + map[pos][j];//對邊進行松弛 } } } return dis[target]; } int main(){ int m; while(scanf("%d%d",&n,&m)!=EOF){ int i; int j; for(i = 1 ; i <= n ; ++i){ for(j = 1 ; j <= n ; ++j){ if(i == j){ map[i][j] = 0; }else{ map[i][j] = inf; } } } for(i = 1 ; i <= m ; ++i){ int a,b,c; scanf("%d%d%d",&a,&b,&c); map[a][b] = map[b][a] = c;//這裏默認是無向圖。。所以要兩個方向都做處理,僅僅做一個方向上的處理會WA } target = n; int result = dijkstra(1); printf("%d\n",result); } return 0; }
三、使用bellman-ford算法
bellmen-ford算法介紹:
思想:事實上bellman-ford的思想和dijkstra的是非常像的,其關鍵點都在於不斷地對邊進行松弛。
而最大的差別就在於前者能作用於負邊權的情況。事實上現思路還是在求出最短路徑後。推斷此刻是否還能對便進行松弛,假設還能進行松弛,便說明還有負邊權的邊
實現:
bool bellmen_ford(){ int i; for(i = 1 ; i <= n ; ++i){//初始化 dis[i] = inf; } dis[source] = 0;//源節點到自己的距離為0 int j; for(i = 1 ; i < n ; ++i){//計算最短路徑 for(j = 1 ; j <= m ; ++j){ if(dis[edge[j].v] > dis[edge[j].u] + edge[j].weight){ dis[edge[j].v] = dis[edge[j].u] + edge[j].weight; } if(dis[edge[j].u] > dis[edge[j].v] + edge[j].weight){ dis[edge[j].u] = dis[edge[j].v] + edge[j].weight; } } } for(j = 1 ; j <= m ; ++j){//推斷是否有負邊權的邊 if(dis[edge[j].v] > dis[edge[j].u] + edge[j].weight){ return false; } } return true; }
基本結構:
struct Edge{ int u; int v; int weight; }; Edge edge[maxm];//用來存儲邊 int dis[maxn];//dis[i]表示源點到i的距離.一開始是估算距離
條件:事實上求最短路徑的題目的基本條件都是點數、邊數、起點、終點
一下給出這一道題的bellman-ford的實現方法
/* * NEFU_207_BF.cpp * * Created on: 2014年5月28日 * Author: Administrator */ #include <iostream> #include <cstdio> using namespace std; const int maxn = 105; const int maxm = 105; struct Edge{ int u; int v; int weight; }; Edge edge[maxm];//用來存儲邊 int dis[maxn];//dis[i]表示源點到i的距離.一開始是估算距離 const int inf = 1000000; int source; int n,m; bool bellmen_ford(){ int i; for(i = 1 ; i <= n ; ++i){//初始化 dis[i] = inf; } dis[source] = 0;//源節點到自己的距離為0 int j; for(i = 1 ; i < n ; ++i){//計算最短路徑 for(j = 1 ; j <= m ; ++j){ if(dis[edge[j].v] > dis[edge[j].u] + edge[j].weight){ dis[edge[j].v] = dis[edge[j].u] + edge[j].weight; } if(dis[edge[j].u] > dis[edge[j].v] + edge[j].weight){ dis[edge[j].u] = dis[edge[j].v] + edge[j].weight; } } } for(j = 1 ; j <= m ; ++j){//推斷是否有負邊權的邊 if(dis[edge[j].v] > dis[edge[j].u] + edge[j].weight){ return false; } } return true; } int main(){ while(scanf("%d%d",&n,&m)!=EOF){ int i; for(i = 1 ; i <= m ; ++i){ scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].weight); } source = 1; bellmen_ford(); printf("%d\n",dis[n]); } return 0; }
四、使用spfa算法來解決。
思想:用於求單源最短路徑,能夠適用於負邊權的情況。spfa(Shortest Path Faster Algorithm)算法事實上不是什麽非常難理解的算法。它僅僅是bellman-ford的隊列優化而已。
模板:
#include <iostream> #include <cstring> #include <queue> using namespace std; const int N = 105; const int INF = 99999999; int map[N][N], dist[N]; bool visit[N]; int n, m; void init() {//初始化 int i, j; for (i = 1; i < N; i++) { for (j = 1; j < N; j++) { if (i == j) { map[i][j] = 0; } else { map[i][j] = map[j][i] = INF; } } } } /** * SPFA算法. * 使用spfa算法來求單元最短路徑 * 參數說明: * start:起點 */ void spfa(int start) { queue<int> Q; int i, now; memset(visit, false, sizeof(visit)); for (i = 1; i <= n; i++){ dist[i] = INF; } dist[start] = 0; Q.push(start); visit[start] = true; while (!Q.empty()) { now = Q.front(); Q.pop(); visit[now] = false; for (i = 1; i <= n; i++) { if (dist[i] > dist[now] + map[now][i]) { dist[i] = dist[now] + map[now][i]; if (visit[i] == 0) { Q.push(i); visit[i] = true; } } } } }
這道題的代碼例如以下:
/* * NEFU207.CPP * * Created on: 2015年3月26日 * Author: Administrator */ #include <iostream> #include <cstring> #include <queue> using namespace std; const int N = 105; const int INF = 99999999; int map[N][N], dist[N]; bool visit[N]; int n, m; void init() {//初始化 int i, j; for (i = 1; i < N; i++) { for (j = 1; j < N; j++) { if (i == j) { map[i][j] = 0; } else { map[i][j] = map[j][i] = INF; } } } } /** * SPFA算法. * 使用spfa算法來求單元最短路徑 * 參數說明: * start:起點 */ void spfa(int start) { queue<int> Q; int i, now; memset(visit, false, sizeof(visit)); for (i = 1; i <= n; i++){ dist[i] = INF; } dist[start] = 0; Q.push(start); visit[start] = true; while (!Q.empty()) { now = Q.front(); Q.pop(); visit[now] = false; for (i = 1; i <= n; i++) { if (dist[i] > dist[now] + map[now][i]) { dist[i] = dist[now] + map[now][i]; if (visit[i] == 0) { Q.push(i); visit[i] = true; } } } } } int main(){ while(scanf("%d%d",&n,&m)!=EOF){ init(); while(m--){ int a,b,c; scanf("%d%d%d",&a,&b,&c); if(map[a][b] > c){ map[a][b] = map[b][a] = c; } } spfa(1); printf("%d\n",dist[n]); } return 0; }
2、NEFU 313 最短路徑問題
題目與分析:
這一道題。抽象一下。還是“求從a到b的最短距離”。相同能夠使用floyd和dijkstra來做。
和上面那道題有點不同的地方就是:由序號點(用序號來描寫敘述的點)變成了xy點(用坐標系來描寫敘述的點)....算法部分該怎麽寫還是怎麽寫。。僅僅是
觀察一下。題目已經給出點數、邊數、起點、終點。
在“最短路徑”的對應的題目中。5個基本條件中已經知道了4個,還差邊的信息。即map[][]數據的記錄不再有題目給出,而是須要自己寫一個distance函數來計算一下
1、floyd
/* * NEFU_313.cpp * * Created on: 2014年5月27日 * Author: pc */ #include <iostream> #include <cstdio> #include <cmath> using namespace std; const int maxn = 105; double map[maxn][maxn]; int n; const int inf = INT_MAX; struct Pointt { double x; double y; }; double distance1(Pointt p1, Pointt p2) { return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)); } void initial() { int i; int j; for (i = 1; i <= n; ++i) { for (j = 1; j <= n; ++j) { if (i == j) { map[i][j] = 0; } else { map[i][j] = inf; } } } } void floyd() { int i; int j; int k; for (k = 1; k <= n; ++k) { for (i = 1; i <= n; ++i) { for (j = 1; j <= n; ++j) { if (map[i][j] > map[i][k] + map[k][j]) { map[i][j] = map[i][k] + map[k][j]; } } } } } int main() { while (scanf("%d", &n) != EOF) { int i; Pointt p[n + 1]; for (i = 1; i <= n; ++i) { scanf("%lf%lf", &p[i].x, &p[i].y); } int m; scanf("%d", &m); initial(); for (i = 1; i <= m; ++i) { int a, b; scanf("%d%d", &a, &b); map[a][b] = map[b][a] = distance1(p[a], p[b]); } floyd(); int start, end; scanf("%d%d", &start, &end); printf("%.2lf\n", map[start][end]); } return 0; }
2、dijkstra
/* * NEFU_313.cpp * * Created on: 2014年5月27日 * Author: pc */ #include <iostream> #include <cstdio> #include <cmath> using namespace std; const int maxn = 105; const int inf = INT_MAX; int s[maxn]; double dis[maxn]; double map[maxn][maxn]; int n; int target; struct Pointt{ double x; double y; }; double distance1(Pointt p1, Pointt p2){ return sqrt((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y)); } double dijkstra(int v){ int i; for(i =1 ; i <= n ; ++i){ s[i] = 0; dis[i] = map[v][i]; } for(i = 1 ; i < n; ++i){ double min = inf; int pos; int j; for(j = 1 ; j <= n ; ++j){ if(!s[j] && dis[j] < min){ min = dis[j]; pos = j; } } s[pos] = 1; for(j = 1 ; j <= n ; ++j){ if(!s[j] && dis[j] > dis[pos] + map[pos][j]){ dis[j] = dis[pos] + map[pos][j]; } } } return dis[target]; } void printfMap(){ int i; int j; for(i = 1 ; i <= n ; ++i){ for(j = 1 ; j <= n ; ++j){ printf("%lf " ,map[i][j]); } printf("\n"); } } int main(){ while(scanf("%d",&n)!=EOF){ Pointt p[n+1]; int i; for(i = 1 ; i <= n ; ++i){ scanf("%lf%lf",&p[i].x,&p[i].y); } int j; for(i = 1 ; i <= n ; ++i){ for(j = 1 ; j <= n ; ++j){ if(i == j){ map[i][j] = 0; }else{ map[i][j] = inf; } } } int m; scanf("%d",&m); for(i = 1 ; i <= m ; ++i){ int a,b; scanf("%d%d",&a,&b); map[a][b] = map[b][a] = distance1(p[a],p[b]); } int start; scanf("%d%d",&start,&target); double result = dijkstra(start); printf("%.2lf\n",result); } return 0; }
下面是再次做這道題的時候的代碼:
/* * NEFU_313.cpp * * Created on: 2014年9月6日 * Author: pc */ #include <iostream> #include <cstdio> #include <math.h> using namespace std; const int maxn = 105; const int inf = 99999; int s[maxn]; double dis[maxn]; double map[maxn][maxn]; int n; int target; struct Point{ int x; int y; }p[maxn]; double mydistance(Point a,Point b){ return sqrt(pow(a.x-b.x,2) + pow(a.y - b.y,2)); } void initial(){ int i; int j; for(i = 1 ; i <= n ; ++i){ for(j = 1 ; j <= n ; ++j){ if(i == j){ map[i][j] = 0; }else{ map[i][j] = inf; } } } } double dijkstra(int v){ int i; for(i = 1 ; i <= n ; ++i){ s[i] = false; dis[i] = map[v][i]; } int j; for(i = 1 ; i < n ; ++i){ double min = inf; int pos; for(j = 1 ; j <= n ; ++j){ if(!s[j] && min > dis[j]){ min = dis[j]; pos = j; } } s[pos] = true; for(j = 1 ; j <= n ; ++j){ if(!s[j] && dis[j] > dis[pos] + map[pos][j]){ dis[j] = dis[pos] + map[pos][j]; } } } return dis[target]; } int main(){ while(scanf("%d",&n)!=EOF){ int i; for(i = 1 ; i <= n ; ++i){ scanf("%d%d",&p[i].x,&p[i].y); } initial(); int m; scanf("%d",&m); for(i = 1 ; i <= m ; ++i){ int a,b; scanf("%d%d",&a,&b); double c = mydistance(p[a],p[b]); if(map[a][b] > c){ map[a][b] = map[b][a] = c;//註意,這裏是無向圖,還是得做一下處理才好,否則會WA } } int v; scanf("%d%d",&v,&target); double result = dijkstra(v); printf("%.2lf\n",result); } return 0; }
3)spfa算法
/* * NEFU313.cpp * * Created on: 2015年3月26日 * Author: Administrator */ #include <iostream> #include <cstring> #include <queue> #include <cmath> using namespace std; const int N = 105; const int INF = 99999999; struct Point{ double x; double y; }points[N]; double getDistance(Point p1,Point p2){ return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)); } double map[N][N]; double dist[N]; bool visit[N]; int n, m; void init() {//初始化 int i, j; for (i = 1; i < N; i++) { for (j = 1; j < N; j++) { if (i == j) { map[i][j] = 0; } else { map[i][j] = map[j][i] = INF; } } } } /** * SPFA算法. * 使用spfa算法來求單元最短路徑 * 參數說明: * start:起點 */ void spfa(int start) { queue<int> Q; int i, now; memset(visit, false, sizeof(visit)); for (i = 1; i <= n; i++){ dist[i] = INF; } dist[start] = 0; Q.push(start); visit[start] = true; while (!Q.empty()) { now = Q.front(); Q.pop(); visit[now] = false; for (i = 1; i <= n; i++) { if (dist[i] > dist[now] + map[now][i]) { dist[i] = dist[now] + map[now][i]; if (visit[i] == 0) { Q.push(i); visit[i] = true; } } } } } int main(){ while(scanf("%d",&n)!=EOF){ init(); int i; for(i = 1 ; i <= n ; ++i){ scanf("%lf%lf",&points[i].x,&points[i].y); } scanf("%d",&m); while(m--){ int a,b; scanf("%d%d",&a,&b); map[a][b] = map[b][a] = getDistance(points[a],points[b]); } int start,end; scanf("%d%d",&start,&end); spfa(start); printf("%.2lf\n",dist[end]); } }
3、NEFU 208 宮鎖珠簾
題目與分析:
這道題抽象一下,還是“求從a到b的最短距離”。。相同能夠使用floyd和dijkstra來做。。
這道題與前面的不同的地方在於:兩個點之間可能有多條路(我們保存那條最短的就可以)。
另外,還要理解dijkstra和floyd算法中使用到的map[][]矩陣的含義。
map[i][i] = 0.自己到自己的距離為0
map[i][j] = inf .表示兩點之間無法連通
下面是分別用dijkstra、floyd、spfa這三種算法來做的代碼。須要註意的是這道題頂點序號的範圍是0~n-1,而之前做的題目的定點序號範圍都是1~n。
1、floyd
/* * NEFU_208.cpp * * Created on: 2014年5月27日 * Author: pc */ #include <iostream> #include <cstdio> #include <cmath> using namespace std; const int maxn = 105; const int inf = 10005; //const int inf = INT_MAX; //註意不要輕易使用INT_MAX.假設這裏使用了INT_MAX,那麽假設2個inf相加的話,那麽久整數溢出了... int n; int map[maxn][maxn]; void initial(){ int i; int j; for(i = 0 ; i < n ; ++i){ for(j = 0 ; j < n ; ++j){ if(i == j){ map[i][j] = 0; }else{ map[i][j] = inf; } } } } void floyd(){ int i; int j; int k; for( k = 0 ; k < n ; ++k){ for(i = 0 ; i < n ; ++i){ for(j = 0 ; j < n ; ++j){ if(map[i][j] > map[i][k] + map[k][j]){ map[i][j] = map[i][k] + map[k][j]; } } } } } void printfMap(){ int i; int j; for(i = 0 ; i < n ; ++i){ for(j = 0 ; j < n ; ++j){ printf("%d " ,map[i][j]); } printf("\n"); } } int main(){ int m; while(scanf("%d%d",&n,&m)!=EOF){ initial(); int i; for(i = 1 ; i <= m ; ++i){ int a,b,c; scanf("%d%d%d",&a,&b,&c); if(c < map[a][b]){//用來解決兩個點之間可能有多條道路的問題 map[a][b] = map[b][a] = c; } } floyd(); int start,end; scanf("%d%d",&start,&end); if(map[start][end] == inf){ printf("-1\n"); }else{ printf("%d\n",map[start][end]); } } return 0; }
2、dijkstra
/* * NEFU_208.cpp * * Created on: 2014年5月27日 * Author: pc */ #include <iostream> #include <cstdio> using namespace std; const int maxn = 105; const int inf = 10005; int n; int s[maxn]; int dis[maxn]; int map[maxn][maxn]; int target; int dijkstra(int v){ int i; for(i = 0 ; i < n ; ++i){ s[i] = 0; dis[i] = map[v][i]; } for(i = 0 ; i < n-1 ; ++i){//這裏的意思實際上是將剩下的n-1個點全部放到S集合中 int min = inf; int pos; int j; for(j = 0 ; j < n ; ++j){//尋找最短路徑點 if(!s[j] && dis[j] < min){ min = dis[j]; pos = j; } } s[pos] = 1; for(j = 0 ; j < n ; ++j){ if(!s[j] && dis[j] > dis[pos] + map[pos][j]){ dis[j] = dis[pos] + map[pos][j]; } } } return dis[target]; } int main(){ int m; while(scanf("%d%d",&n,&m)!=EOF){ int i; int j; for(i = 0 ; i < n ; ++i){ for(j = 0 ; j < n ; ++j){ if(i == j){ map[i][j] = 0; }else{ map[i][j] = inf; } } } for(i = 1 ; i <= m ; ++i){ int a,b,c; scanf("%d%d%d",&a,&b,&c); if(map[a][b] > c){ map[a][b] = map[b][a] = c; } } int start,end; scanf("%d%d",&start,&end); target = end; int result = dijkstra(start); if(result == inf){ printf("-1\n"); }else{ printf("%d\n",result); } } return 0; }
3、spfa算法
/* * NEFU208.cpp * * Created on: 2015年3月26日 * Author: Administrator */ #include <iostream> #include <cstring> #include <queue> using namespace std; const int N = 105; const int INF = 99999999; int map[N][N], dist[N]; bool visit[N]; int n, m; void init() {//初始化 int i, j; for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { if (i == j) { map[i][j] = 0; } else { map[i][j] = map[j][i] = INF; } } } } /** * SPFA算法. * 使用spfa算法來求單元最短路徑 * 參數說明: * start:起點 */ void spfa(int start) { queue<int> Q; int i, now; memset(visit, false, sizeof(visit)); for (i = 0; i < n; i++){ dist[i] = INF; } dist[start] = 0; Q.push(start); visit[start] = true; while (!Q.empty()) { now = Q.front(); Q.pop(); visit[now] = false; for (i = 0; i < n; i++) {//須要註意一下的是,這道題頂點的序號是從0開始的,到n-1.之前的題目都是1~n if (dist[i] > dist[now] + map[now][i]) { dist[i] = dist[now] + map[now][i]; if (visit[i] == 0) { Q.push(i); visit[i] = true; } } } } } int main(){ while(scanf("%d%d",&n,&m)!=EOF){ init(); while(m--){ int a,b,c; scanf("%d%d%d",&a,&b,&c); if(map[a][b] > c){ map[a][b] = map[b][a] = c; } } int start,end; scanf("%d%d",&start,&end); spfa(start); if(dist[end] == INF){ printf("-1\n"); }else{ printf("%d\n",dist[end]); } } return 0; }
(最短路徑算法整理)dijkstra、floyd、bellman-ford、spfa算法模板的整理與介紹