1. 程式人生 > >(最短路徑算法整理)dijkstra、floyd、bellman-ford、spfa算法模板的整理與介紹

(最短路徑算法整理)dijkstra、floyd、bellman-ford、spfa算法模板的整理與介紹

void empty borde fast 默認 grand else 理解 scan


這一篇博客以一些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算法模板的整理與介紹