(最短路徑演算法整理)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;
}