最短路径模板

 这一篇博客以一些OJ上的题目为载体,整理一下最短路径算法。会陆续的更新。。。

   


一、多源最短路算法——floyd算法

       floyd算法主要用于求任意两点间的最短路径,也成最短最短路径问题。

       核心代码:

       

[cpp]  view plain  copy
  1. /** 
  2.  *floyd算法 
  3.  */  
  4. void floyd() {  
  5.     int i, j, k;  
  6.     for (k = 1; k <= n; ++k) {//遍历所有的中间点  
  7.         for (i = 1; i <= n; ++i) {//遍历所有的起点  
  8.             for (j = 1; j <= n; ++j) {//遍历所有的终点  
  9.                 if (e[i][j] > e[i][k] + e[k][j]) {//如果当前i-->j的距离大于i-->k--->j的距离之和  
  10.                     e[i][j] = e[i][k] + e[k][j];//更新从i--->j的最短路径  
  11.                 }  
  12.             }  
  13.         }  
  14.     }  
  15. }  

    时间复杂度:O(N^3)

    不能使用的情况:边中含有负权值


例题:

1、WIKIOI 1077  多源最短路 

分析:这道题是floyd的裸题。大家只要理解了floyd的思想以后,基本很快就能解答出来了。唯一需要注意的地方就是

这道题的map[][]矩阵中的顶点默认是从1开始。如果顶点是从0开始算的需要做一下处理:printf("%d\n",map[a-1][b-1]);


[cpp]  view plain  copy
  1. /* 
  2.  * 1077.cpp 
  3.  * 
  4.  *  Created on: 2014年5月23日 
  5.  *      Author: pc 
  6.  */  
  7.   
  8. #include <iostream>  
  9. #include <cstdio>  
  10.   
  11. using namespace std;  
  12.   
  13. const int maxn = 105;  
  14. int e[maxn][maxn];  
  15. int n;  
  16.   
  17. const int inf = 99999999;  
  18.   
  19. void initial() {  
  20.     int i, j;  
  21.     for (i = 1; i <= n; ++i) {  
  22.         for (j = 1; j <= n; ++j) {  
  23.             if (i == j) {  
  24.                 e[i][j] = 0;  
  25.             } else {  
  26.                 e[i][j] = inf;  
  27.             }  
  28.         }  
  29.     }  
  30. }  
  31.   
  32. /** 
  33.  *floyd算法 
  34.  */  
  35. void floyd() {  
  36.     int i, j, k;  
  37.     for (k = 1; k <= n; ++k) {//遍历所有的中间点  
  38.         for (i = 1; i <= n; ++i) {//遍历所有的起点  
  39.             for (j = 1; j <= n; ++j) {//遍历所有的终点  
  40.                 if (e[i][j] > e[i][k] + e[k][j]) {//如果当前i-->j的距离大于i-->k--->j的距离之和  
  41.                     e[i][j] = e[i][k] + e[k][j];//更新从i--->j的最短路径  
  42.                 }  
  43.             }  
  44.         }  
  45.     }  
  46. }  
  47.   
  48. int main() {  
  49.     while (scanf("%d", &n) != EOF) {  
  50.   
  51.         initial();  
  52.   
  53.         int i, j;  
  54.         for (i = 1; i <= n; ++i) {  
  55.             for (j = 1; j <= n; ++j) {  
  56.                 scanf("%d", &e[i][j]);  
  57.             }  
  58.         }  
  59.   
  60.         floyd();  
  61.         int q;  
  62.         scanf("%d", &q);  
  63.         while (q--) {  
  64.             int a, b;  
  65.             scanf("%d %d", &a, &b);  
  66.   
  67.             printf("%d\n", e[a][b]);  
  68.         }  
  69.   
  70.     }  
  71.   
  72.     return 0;  
  73. }  


以下是自己再次做这道题的时候的代码:

[cpp]  view plain  copy
  1. /* 
  2.  * WIKIOI_1077.cpp 
  3.  * 
  4.  *  Created on: 2014年9月6日 
  5.  *      Author: pc 
  6.  */  
  7.   
  8.   
  9. #include <iostream>  
  10. #include <cstdio>  
  11.   
  12. const int maxn = 105;  
  13. const int inf = 999999;  
  14.   
  15. int map[maxn][maxn];  
  16.   
  17. void initial(int n){  
  18.     int i;  
  19.     int j;  
  20.     for(i = 0 ; i < n ; ++i){  
  21.         for(j = 0 ; j < n ; ++j){  
  22.             if(i == j){  
  23.                 map[i][j] = 0;  
  24.             }else{  
  25.                 map[i][j] =  inf;  
  26.             }  
  27.         }  
  28.     }  
  29. }  
  30.   
  31. void floyd(int n){  
  32.     int i;  
  33.     int j;  
  34.     int k;  
  35.     for(k = 0 ; k < n ; ++k){//顶点从0开始算》。。  
  36.         for(i = 0 ; i < n ; ++i){  
  37.             for(j = 0 ; j < n ; ++j){  
  38.                 if(map[i][j] > map[i][k] + map[k][j]){  
  39.                     map[i][j] = map[i][k] + map[k][j];  
  40.                 }  
  41.             }  
  42.         }  
  43.     }  
  44. }  
  45.   
  46.   
  47. int main(){  
  48.     int n;  
  49.     scanf("%d",&n);  
  50.   
  51.     initial(n);  
  52.   
  53.     int i;  
  54.     int j;  
  55.     for(i = 0 ; i < n ; ++i){  
  56.         for(j = 0 ; j < n ; ++j){  
  57.             int c;  
  58.             scanf("%d",&c);  
  59.             map[i][j] = c;  
  60.         }  
  61.     }  
  62.   
  63.     floyd(n);  
  64.   
  65.     int q;  
  66.     scanf("%d",&q);  
  67.     while(q--){  
  68.         int a,b;  
  69.         scanf("%d %d",&a,&b);  
  70.         printf("%d\n",map[a-1][b-1]);  
  71.     }  
  72.   
  73.     return 0;  
  74. }  




二、单源最短路径算法——dijkstra

       1、思想描述:当Q(一开始为所有节点的集合)非空时,不断地将Q中的最小值u取出,然后放到S(最短路径的节点的集合)集合中,然后遍历所有与u邻接的边,如果可以进行松弛,则对便进行相应的松弛。。。

       2、实现

 

[cpp]  view plain  copy
  1. /** 
  2.  * 返回从v---->到target的最短路径 
  3.  */  
  4. int dijkstra(int v){  
  5.     int i;  
  6.     for(i = 1 ; i <= n ; ++i){//初始化  
  7.         s[i] = 0;//一开始,所有的点均为被访问过  
  8.         dis[i] = map[v][i];  
  9.     }  
  10.         dis[v] = 0;   
  11.         s[v] = true;  
  12.     for(i = 1 ; i < n ; ++i){  
  13.         int min = inf;  
  14.         int pos;  
  15.   
  16.         int j;  
  17.         for(j = 1 ; j <= n ; ++j){//寻找目前的最短路径的最小点  
  18.             if(!s[j] && dis[j] < min){  
  19.                 min = dis[j];  
  20.                 pos = j;  
  21.             }  
  22.         }  
  23.   
  24.         s[pos] = 1;  
  25.   
  26.         for(j = 1 ; j <= n ; j++){//遍历u的所有的邻接的边  
  27.             if(!s[j] && dis[j] > dis[pos] + map[pos][j]){  
  28.                 dis[j] = dis[pos] + map[pos][j];//对边进行松弛  
  29.             }  
  30.         }  
  31.     }  
  32.   
  33.   
  34.     return dis[target];  
  35. }  

         3、基本结构

    

[cpp]  view plain  copy
  1. int s[maxn];//用来记录某一点是否被访问过  
  2. int map[maxn][maxn];//地图  
  3. 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

[cpp]  view plain  copy
  1. /* 
  2.  * NEFU_207.cpp 
  3.  * 
  4.  *  Created on: 2014年5月27日 
  5.  *      Author: pc 
  6.  */  
  7.   
  8. #include <iostream>  
  9. #include <cstdio>  
  10.   
  11. using namespace std;  
  12.   
  13. const int maxn = 105;  
  14. const int inf = 99999999;  
  15. int e[maxn][maxn];  
  16.   
  17. int n,m;  
  18.   
  19. void initial(){  
  20.     int i;  
  21.     int j;  
  22.     for(i = 1 ; i <= n ; ++i){  
  23.         for(j = 1 ; j <= n ; ++j){  
  24.             if(i == j){  
  25.                 e[i][j] = 0;  
  26.             }else{  
  27.                 e[i][j] = inf;  
  28.             }  
  29.         }  
  30.     }  
  31. }  
  32.   
  33.   
  34. void floyd(){  
  35.     int i;  
  36.     int j;  
  37.     int k;  
  38.   
  39.     for(k = 1 ; k <= n ; ++k){  
  40.         for(i = 1 ; i <= n ; ++i){  
  41.             for(j = 1 ; j <= n ; ++j){  
  42.                 if(e[i][j] > e[i][k] + e[k][j]){  
  43.                     e[i][j] = e[i][k] + e[k][j];  
  44.                 }  
  45.             }  
  46.         }  
  47.     }  
  48. }  
  49.   
  50.   
  51. int main(){  
  52.     while(scanf("%d%d",&n,&m)!=EOF){  
  53.         initial();  
  54.   
  55.         int i;  
  56.         for(i = 1 ; i <= m ; ++i){  
  57.             int a,b,c;  
  58.             scanf("%d%d%d",&a,&b,&c);  
  59.             e[a][b] = e[b][a] = c;  
  60.         }  
  61.   
  62.         floyd();  
  63.   
  64.         printf("%d\n",e[1][n]);  
  65.     }  
  66.   
  67.     return 0;  
  68. }  


2)使用dijkstra

[cpp]  view plain  copy
  1. /* 
  2.  * NEFU_207.cpp 
  3.  * 
  4.  *  Created on: 2014年5月27日 
  5.  *      Author: pc 
  6.  */  
  7.   
  8.   
  9. #include <iostream>  
  10. #include <cstdio>  
  11.   
  12. using namespace std;  
  13.   
  14. const int maxn = 105;  
  15. const int inf = 9999999;  
  16.   
  17. int s[maxn];//用来记录某一点是否被访问过  
  18. int map[maxn][maxn];//地图  
  19. int dis[maxn];//从原点到某一个点的最短距离(一开始是估算距离)  
  20.   
  21. int n;  
  22. int target;  
  23.   
  24. /** 
  25.  * 返回从v---->到target的最短路径 
  26.  */  
  27. int dijkstra(int v){  
  28.     int i;  
  29.     for(i = 1 ; i <= n ; ++i){//初始化  
  30.         s[i] = 0;//一开始,所有的点均为被访问过  
  31.         dis[i] = map[v][i];  
  32.     }  
  33.   
  34.   
  35.     for(i = 1 ; i < n ; ++i){  
  36.         int min = inf;  
  37.         int pos;  
  38.   
  39.         int j;  
  40.         for(j = 1 ; j <= n ; ++j){//寻找目前的最短路径的最小点  
  41.             if(!s[j] && dis[j] < min){  
  42.                 min = dis[j];  
  43.                 pos = j;  
  44.             }  
  45.         }  
  46.   
  47.         s[pos] = 1;  
  48.   
  49.         for(j = 1 ; j <= n ; j++){//遍历u的所有的邻接的边  
  50.             if(!s[j] && dis[j] > dis[pos] + map[pos][j]){  
  51.                 dis[j] = dis[pos] + map[pos][j];//对边进行松弛  
  52.             }  
  53.         }  
  54.     }  
  55.   
  56.   
  57.     return dis[target];  
  58. }  
  59.   
  60.   
  61.   
  62. int main(){  
  63.     int m;  
  64.     while(scanf("%d%d",&n,&m)!=EOF){  
  65.   
  66.         int i;  
  67.         int j;  
  68.         for(i = 1 ; i <= n ; ++i){  
  69.             for(j = 1 ; j <= n ; ++j){  
  70.                 if(i == j){  
  71.                     map[i][j] = 0;  
  72.                 }else{  
  73.                     map[i][j] = inf;  
  74.                 }  
  75.             }  
  76.         }  
  77.   
  78.   
  79.         for(i = 1 ; i <= m ; ++i){  
  80.             int a,b,c;  
  81.             scanf("%d%d%d",&a,&b,&c);  
  82.   
  83.             map[a][b] = map[b][a] = c;//这里默认是无向图。。所以要两个方向都做处理,只做一个方向上的处理会WA  
  84.         }  
  85.   
  86.         target = n;  
  87.         int result = dijkstra(1);  
  88.   
  89.         printf("%d\n",result);  
  90.     }  
  91.   
  92.     return 0;  
  93. }  


三、使用bellman-ford算法

bellmen-ford算法介绍:

       思想:其实bellman-ford的思想和dijkstra的是很像的,其关键点都在于不断地对边进行松弛。而最大的区别就在于前者能作用于负边权的情况。其实现思路还是在求出最短路径后,判断此刻是否还能对便进行松弛,如果还能进行松弛,便说明还有负边权的边

       实现:

[cpp]  view plain  copy
  1. bool bellmen_ford(){  
  2.     int i;  
  3.     for(i = 1 ; i <= n ; ++i){//初始化  
  4.         dis[i] = inf;  
  5.     }  
  6.   
  7.     dis[source] = 0;//源节点到自己的距离为0  
  8.   
  9.     int j;  
  10.     for(i = 1 ; i < n ; ++i){//计算最短路径  
  11.         for(j = 1 ; j <= m ; ++j){  
  12.             if(dis[edge[j].v] > dis[edge[j].u] + edge[j].weight){  
  13.                 dis[edge[j].v] = dis[edge[j].u] + edge[j].weight;  
  14.             }  
  15.   
  16.             if(dis[edge[j].u] > dis[edge[j].v] + edge[j].weight){  
  17.                 dis[edge[j].u] = dis[edge[j].v] + edge[j].weight;  
  18.             }  
  19.         }  
  20.     }  
  21.   
  22.     for(j = 1 ; j <= m ; ++j){//判断是否有负边权的边  
  23.         if(dis[edge[j].v] > dis[edge[j].u] + edge[j].weight){  
  24.             return false;  
  25.         }  
  26.     }  
  27.   
  28.     return true;  
  29. }  


基本结构:

[cpp]  view plain  copy
  1. struct Edge{  
  2.     int u;  
  3.     int v;  
  4.     int weight;  
  5. };  
  6.   
  7. Edge edge[maxm];//用来存储边  
  8. int dis[maxn];//dis[i]表示源点到i的距离.一开始是估算距离  


 条件:其实求最短路径的题目的基本条件都是点数、边数、起点、终点

一下给出这一道题的bellman-ford的实现方法

[cpp]  view plain  copy
  1. /* 
  2.  * NEFU_207_BF.cpp 
  3.  * 
  4.  *  Created on: 2014年5月28日 
  5.  *      Author: Administrator 
  6.  */  
  7.   
  8. #include <iostream>  
  9. #include <cstdio>  
  10.   
  11. using namespace std;  
  12.   
  13. const int maxn = 105;  
  14. const int maxm = 105;  
  15.   
  16. struct Edge{  
  17.     int u;  
  18.     int v;  
  19.     int weight;  
  20. };  
  21.   
  22. Edge edge[maxm];//用来存储边  
  23. int dis[maxn];//dis[i]表示源点到i的距离.一开始是估算距离  
  24.   
  25. const int inf = 1000000;  
  26.   
  27. int source;  
  28. int n,m;  
  29.   
  30. bool bellmen_ford(){  
  31.     int i;  
  32.     for(i = 1 ; i <= n ; ++i){//初始化  
  33.         dis[i] = inf;  
  34.     }  
  35.   
  36.     dis[source] = 0;//源节点到自己的距离为0  
  37.   
  38.     int j;  
  39.     for(i = 1 ; i < n ; ++i){//计算最短路径  
  40.         for(j = 1 ; j <= m ; ++j){  
  41.             if(dis[edge[j].v] > dis[edge[j].u] + edge[j].weight){  
  42.                 dis[edge[j].v] = dis[edge[j].u] + edge[j].weight;  
  43.             }  
  44.   
  45.             if(dis[edge[j].u] > dis[edge[j].v] + edge[j].weight){  
  46.                 dis[edge[j].u] = dis[edge[j].v] + edge[j].weight;  
  47.             }  
  48.         }  
  49.     }  
  50.   
  51.     for(j = 1 ; j <= m ; ++j){//判断是否有负边权的边  
  52.         if(dis[edge[j].v] > dis[edge[j].u] + edge[j].weight){  
  53.             return false;  
  54.         }  
  55.     }  
  56.   
  57.     return true;  
  58. }  
  59.   
  60. int main(){  
  61.     while(scanf("%d%d",&n,&m)!=EOF){  
  62.         int i;  
  63.         for(i = 1 ; i <= m ; ++i){  
  64.             scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].weight);  
  65.         }  
  66.   
  67.         source = 1;  
  68.   
  69.         bellmen_ford();  
  70.   
  71.         printf("%d\n",dis[n]);  
  72.     }  
  73.   
  74.     return 0;  
  75. }  




四、使用spfa算法来解决。

      思想:用于求单源最短路径,可以适用于负边权的情况。spfa(Shortest Path Faster Algorithm)算法其实不是什么很难理解的算法,它只是bellman-ford的队列优化而已。

      模板:

[cpp]  view plain  copy
  1. #include <iostream>  
  2. #include <cstring>  
  3. #include <queue>  
  4. using namespace std;  
  5.   
  6. const int N = 105;  
  7. const int INF = 99999999;  
  8.   
  9. int map[N][N], dist[N];  
  10. bool visit[N];  
  11. int n, m;  
  12.   
  13. void init() {//初始化  
  14.     int i, j;  
  15.     for (i = 1; i < N; i++) {  
  16.         for (j = 1; j < N; j++) {  
  17.             if (i == j) {  
  18.                 map[i][j] = 0;  
  19.             } else {  
  20.                 map[i][j] = map[j][i] = INF;  
  21.             }  
  22.         }  
  23.     }  
  24. }  
  25.   
  26. /** 
  27.  * SPFA算法. 
  28.  * 使用spfa算法来求单元最短路径 
  29.  * 参数说明: 
  30.  * start:起点 
  31.  */  
  32. void spfa(int start) {  
  33.     queue<int> Q;  
  34.   
  35.     int i, now;  
  36.     memset(visit, falsesizeof(visit));  
  37.     for (i = 1; i <= n; i++){  
  38.         dist[i] = INF;  
  39.     }  
  40.   
  41.     dist[start] = 0;  
  42.     Q.push(start);  
  43.     visit[start] = true;  
  44.     while (!Q.empty()) {  
  45.         now = Q.front();  
  46.         Q.pop();  
  47.         visit[now] = false;  
  48.         for (i = 1; i <= n; i++) {  
  49.             if (dist[i] > dist[now] + map[now][i]) {  
  50.                 dist[i] = dist[now] + map[now][i];  
  51.                 if (visit[i] == 0) {  
  52.                     Q.push(i);  
  53.                     visit[i] = true;  
  54.                 }  
  55.             }  
  56.         }  
  57.     }  
  58. }  


这道题的代码如下:

[cpp]  view plain  copy
  1. /* 
  2.  * NEFU207.CPP 
  3.  * 
  4.  *  Created on: 2015年3月26日 
  5.  *      Author: Administrator 
  6.  */  
  7.   
  8.   
  9. #include <iostream>  
  10. #include <cstring>  
  11. #include <queue>  
  12. using namespace std;  
  13.   
  14. const int N = 105;  
  15. const int INF = 99999999;  
  16.   
  17. int map[N][N], dist[N];  
  18. bool visit[N];  
  19. int n, m;  
  20.   
  21. void init() {//初始化  
  22.     int i, j;  
  23.     for (i = 1; i < N; i++) {  
  24.         for (j = 1; j < N; j++) {  
  25.             if (i == j) {  
  26.                 map[i][j] = 0;  
  27.             } else {  
  28.                 map[i][j] = map[j][i] = INF;  
  29.             }  
  30.         }  
  31.     }  
  32. }  
  33.   
  34. /** 
  35.  * SPFA算法. 
  36.  * 使用spfa算法来求单元最短路径 
  37.  * 参数说明: 
  38.  * start:起点 
  39.  */  
  40. void spfa(int start) {  
  41.     queue<int> Q;  
  42.   
  43.     int i, now;  
  44.     memset(visit, falsesizeof(visit));  
  45.     for (i = 1; i <= n; i++){  
  46.         dist[i] = INF;  
  47.     }  
  48.   
  49.     dist[start] = 0;  
  50.     Q.push(start);  
  51.     visit[start] = true;  
  52.     while (!Q.empty()) {  
  53.         now = Q.front();  
  54.         Q.pop();  
  55.         visit[now] = false;  
  56.         for (i = 1; i <= n; i++) {  
  57.             if (dist[i] > dist[now] + map[now][i]) {  
  58.                 dist[i] = dist[now] + map[now][i];  
  59.                 if (visit[i] == 0) {  
  60.                     Q.push(i);  
  61.                     visit[i] = true;  
  62.                 }  
  63.             }  
  64.         }  
  65.     }  
  66. }  
  67.   
  68. int main(){  
  69.     while(scanf("%d%d",&n,&m)!=EOF){  
  70.         init();  
  71.   
  72.         while(m--){  
  73.             int a,b,c;  
  74.             scanf("%d%d%d",&a,&b,&c);  
  75.   
  76.             if(map[a][b] > c){  
  77.                 map[a][b] = map[b][a] = c;  
  78.             }  
  79.         }  
  80.   
  81.         spfa(1);  
  82.         printf("%d\n",dist[n]);  
  83.     }  
  84.   
  85.     return 0;  
  86. }  





2、NEFU 313 最短路径问题

题目与分析:

       这一道题,抽象一下,还是“求从a到b的最短距离”。同样可以使用floyd和dijkstra来做。和上面那道题有点不同的地方就是:由序号点(用序号来描述的点)变成了xy点(用坐标系来描述的点)....算法部分该怎么写还是怎么写。。只是


观察一下,题目已经给出点数、边数、起点、终点。在“最短路径”的相应的题目中,5个基本条件中已经知道了4个,还差边的信息。即map[][]数据的记录不再有题目给出,而是需要自己写一个distance函数来计算一下


1、floyd

[cpp]  view plain  copy
  1. /* 
  2.  * NEFU_313.cpp 
  3.  * 
  4.  *  Created on: 2014年5月27日 
  5.  *      Author: pc 
  6.  */  
  7.   
  8. #include <iostream>  
  9. #include <cstdio>  
  10. #include <cmath>  
  11.   
  12. using namespace std;  
  13.   
  14. const int maxn = 105;  
  15.   
  16. double map[maxn][maxn];  
  17.   
  18. int n;  
  19. const int inf = INT_MAX;  
  20. struct Pointt {  
  21.     double x;  
  22.     double y;  
  23. };  
  24.   
  25. double distance1(Pointt p1, Pointt p2) {  
  26.     return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));  
  27. }  
  28.   
  29. void initial() {  
  30.     int i;  
  31.     int j;  
  32.   
  33.     for (i = 1; i <= n; ++i) {  
  34.         for (j = 1; j <= n; ++j) {  
  35.             if (i == j) {  
  36.                 map[i][j] = 0;  
  37.             } else {  
  38.                 map[i][j] = inf;  
  39.             }  
  40.         }  
  41.     }  
  42. }  
  43. void floyd() {  
  44.     int i;  
  45.     int j;  
  46.   
  47.     int k;  
  48.     for (k = 1; k <= n; ++k) {  
  49.         for (i = 1; i <= n; ++i) {  
  50.             for (j = 1; j <= n; ++j) {  
  51.                 if (map[i][j] > map[i][k] + map[k][j]) {  
  52.                     map[i][j] = map[i][k] + map[k][j];  
  53.                 }  
  54.             }  
  55.         }  
  56.     }  
  57. }  
  58.   
  59. int main() {  
  60.     while (scanf("%d", &n) != EOF) {  
  61.         int i;  
  62.   
  63.         Pointt p[n + 1];  
  64.   
  65.         for (i = 1; i <= n; ++i) {  
  66.             scanf("%lf%lf", &p[i].x, &p[i].y);  
  67.         }  
  68.   
  69.         int m;  
  70.         scanf("%d", &m);  
  71.   
  72.         initial();  
  73.   
  74.         for (i = 1; i <= m; ++i) {  
  75.             int a, b;  
  76.             scanf("%d%d", &a, &b);  
  77.   
  78.             map[a][b] = map[b][a] = distance1(p[a], p[b]);  
  79.         }  
  80.   
  81.         floyd();  
  82.   
  83.         int start, end;  
  84.         scanf("%d%d", &start, &end);  
  85.   
  86.         printf("%.2lf\n", map[start][end]);  
  87.   
  88.     }  
  89.   
  90.     return 0;  
  91. }  



2、dijkstra

[cpp]  view plain  copy
  1. /* 
  2.  * NEFU_313.cpp 
  3.  * 
  4.  *  Created on: 2014年5月27日 
  5.  *      Author: pc 
  6.  */  
  7.   
  8.   
  9. #include <iostream>  
  10. #include <cstdio>  
  11. #include <cmath>  
  12.   
  13. using namespace std;  
  14.   
  15. const int maxn = 105;  
  16. const int inf = INT_MAX;  
  17.   
  18. int s[maxn];  
  19. double dis[maxn];  
  20. double map[maxn][maxn];  
  21.   
  22. int n;  
  23. int target;  
  24.   
  25. struct Pointt{  
  26.     double x;  
  27.     double y;  
  28. };  
  29.   
  30. double distance1(Pointt p1, Pointt p2){  
  31.     return sqrt((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y));  
  32. }  
  33.   
  34. double dijkstra(int v){  
  35.     int i;  
  36.     for(i =1 ; i <= n ; ++i){  
  37.         s[i] = 0;  
  38.         dis[i] = map[v][i];  
  39.     }  
  40.   
  41.   
  42.   
  43.     for(i = 1 ; i < n; ++i){  
  44.         double min = inf;  
  45.         int pos;  
  46.   
  47.         int j;  
  48.         for(j = 1 ; j <= n ; ++j){  
  49.             if(!s[j] && dis[j] < min){  
  50.                 min = dis[j];  
  51.                 pos = j;  
  52.             }  
  53.         }  
  54.   
  55.         s[pos] = 1;  
  56.   
  57.         for(j = 1 ; j <= n ; ++j){  
  58.             if(!s[j] && dis[j] > dis[pos] + map[pos][j]){  
  59.                 dis[j] = dis[pos] + map[pos][j];  
  60.             }  
  61.         }  
  62.     }  
  63.     return  dis[target];  
  64. }  
  65.   
  66.   
  67. void printfMap(){  
  68.     int i;  
  69.     int j;  
  70.     for(i = 1 ; i <= n ; ++i){  
  71.         for(j = 1 ; j <= n ; ++j){  
  72.             printf("%lf " ,map[i][j]);  
  73.         }  
  74.   
  75.         printf("\n");  
  76.     }  
  77. }  
  78.   
  79. int main(){  
  80.     while(scanf("%d",&n)!=EOF){  
  81.         Pointt p[n+1];  
  82.   
  83.         int i;  
  84.         for(i = 1 ; i <= n ; ++i){  
  85.             scanf("%lf%lf",&p[i].x,&p[i].y);  
  86.         }  
  87.   
  88.         int j;  
  89.         for(i = 1 ; i <= n ; ++i){  
  90.             for(j = 1 ; j <= n ; ++j){  
  91.                 if(i == j){  
  92.                     map[i][j] = 0;  
  93.                 }else{  
  94.                     map[i][j] = inf;  
  95.                 }  
  96.             }  
  97.         }  
  98.   
  99.   
  100.         int m;  
  101.         scanf("%d",&m);  
  102.         for(i = 1 ; i <= m ; ++i){  
  103.             int a,b;  
  104.             scanf("%d%d",&a,&b);  
  105.             map[a][b] = map[b][a] = distance1(p[a],p[b]);  
  106.         }  
  107.   
  108.         int start;  
  109.         scanf("%d%d",&start,&target);  
  110.   
  111.   
  112.         double result = dijkstra(start);  
  113.   
  114.         printf("%.2lf\n",result);  
  115.     }  
  116.   
  117.     return 0;  
  118. }  


以下是再次做这道题的时候的代码:

[cpp]  view plain  copy
  1. /* 
  2.  * NEFU_313.cpp 
  3.  * 
  4.  *  Created on: 2014年9月6日 
  5.  *      Author: pc 
  6.  */  
  7.   
  8. #include <iostream>  
  9. #include <cstdio>  
  10. #include <math.h>  
  11.   
  12.   
  13. using namespace std;  
  14.   
  15. const int maxn = 105;  
  16. const int inf = 99999;  
  17.   
  18.   
  19. int s[maxn];  
  20. double dis[maxn];  
  21. double map[maxn][maxn];  
  22.   
  23. int n;  
  24. int target;  
  25.   
  26. struct Point{  
  27.     int x;  
  28.     int y;  
  29. }p[maxn];  
  30.   
  31. double mydistance(Point a,Point b){  
  32.   
  33.     return sqrt(pow(a.x-b.x,2) + pow(a.y - b.y,2));  
  34. }  
  35.   
  36.   
  37. void initial(){  
  38.     int i;  
  39.     int j;  
  40.     for(i = 1 ; i <= n ; ++i){  
  41.         for(j = 1 ; j <= n ; ++j){  
  42.             if(i == j){  
  43.                 map[i][j] = 0;  
  44.             }else{  
  45.                 map[i][j] = inf;  
  46.             }  
  47.         }  
  48.     }  
  49. }  
  50.   
  51.   
  52. double dijkstra(int v){  
  53.     int i;  
  54.     for(i = 1 ; i <= n ; ++i){  
  55.         s[i] = false;  
  56.         dis[i] = map[v][i];  
  57.     }  
  58.   
  59.     int j;  
  60.     for(i = 1 ; i < n ; ++i){  
  61.         double min = inf;  
  62.         int pos;  
  63.   
  64.         for(j = 1 ; j <= n ; ++j){  
  65.             if(!s[j] && min > dis[j]){  
  66.                 min = dis[j];  
  67.                 pos = j;  
  68.             }  
  69.         }  
  70.   
  71.         s[pos] = true;  
  72.   
  73.   
  74.         for(j = 1 ; j <= n ; ++j){  
  75.             if(!s[j] && dis[j] > dis[pos] + map[pos][j]){  
  76.                 dis[j] = dis[pos] + map[pos][j];  
  77.             }  
  78.         }  
  79.     }  
  80.   
  81.     return dis[target];  
  82. }  
  83.   
  84.   
  85.   
  86. int main(){  
  87.     while(scanf("%d",&n)!=EOF){  
  88.         int i;  
  89.         for(i = 1 ; i <= n ; ++i){  
  90.             scanf("%d%d",&p[i].x,&p[i].y);  
  91.         }  
  92.   
  93.         initial();  
  94.   
  95.         int m;  
  96.         scanf("%d",&m);  
  97.         for(i = 1 ; i <= m ; ++i){  
  98.             int a,b;  
  99.             scanf("%d%d",&a,&b);  
  100.   
  101.             double c = mydistance(p[a],p[b]);  
  102.             if(map[a][b] > c){  
  103.                 map[a][b] = map[b][a] = c;//注意,这里是无向图,还是得做一下处理才好,否则会WA  
  104.             }  
  105.         }  
  106.   
  107.   
  108.         int v;  
  109.         scanf("%d%d",&v,&target);  
  110.   
  111.         double result = dijkstra(v);  
  112.   
  113.         printf("%.2lf\n",result);  
  114.   
  115.     }  
  116.   
  117.     return 0;  
  118. }  


3)spfa算法

[cpp]  view plain  copy
  1. /* 
  2.  * NEFU313.cpp 
  3.  * 
  4.  *  Created on: 2015年3月26日 
  5.  *      Author: Administrator 
  6.  */  
  7.   
  8.   
  9.   
  10.   
  11. #include <iostream>  
  12. #include <cstring>  
  13. #include <queue>  
  14. #include <cmath>  
  15.   
  16.   
  17. using namespace std;  
  18.   
  19. const int N = 105;  
  20. const int INF = 99999999;  
  21.   
  22. struct Point{  
  23.     double x;  
  24.     double y;  
  25. }points[N];  
  26.   
  27. double getDistance(Point p1,Point p2){  
  28.     return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));  
  29. }  
  30.   
  31. double map[N][N];  
  32. double dist[N];  
  33. bool visit[N];  
  34. int n, m;  
  35.   
  36. void init() {//初始化  
  37.     int i, j;  
  38.     for (i = 1; i < N; i++) {  
  39.         for (j = 1; j < N; j++) {  
  40.             if (i == j) {  
  41.                 map[i][j] = 0;  
  42.             } else {  
  43.                 map[i][j] = map[j][i] = INF;  
  44.             }  
  45.         }  
  46.     }  
  47. }  
  48.   
  49. /** 
  50.  * SPFA算法. 
  51.  * 使用spfa算法来求单元最短路径 
  52.  * 参数说明: 
  53.  * start:起点 
  54.  */  
  55. void spfa(int start) {  
  56.     queue<int> Q;  
  57.   
  58.     int i, now;  
  59.     memset(visit, falsesizeof(visit));  
  60.     for (i = 1; i <= n; i++){  
  61.         dist[i] = INF;  
  62.     }  
  63.   
  64.     dist[start] = 0;  
  65.     Q.push(start);  
  66.     visit[start] = true;  
  67.     while (!Q.empty()) {  
  68.         now = Q.front();  
  69.         Q.pop();  
  70.         visit[now] = false;  
  71.         for (i = 1; i <= n; i++) {  
  72.             if (dist[i] > dist[now] + map[now][i]) {  
  73.                 dist[i] = dist[now] + map[now][i];  
  74.                 if (visit[i] == 0) {  
  75.                     Q.push(i);  
  76.                     visit[i] = true;  
  77.                 }  
  78.             }  
  79.         }  
  80.     }  
  81. }  
  82.   
  83. int main(){  
  84.     while(scanf("%d",&n)!=EOF){  
  85.         init();  
  86.   
  87.         int i;  
  88.         for(i = 1 ; i <= n ; ++i){  
  89.             scanf("%lf%lf",&points[i].x,&points[i].y);  
  90.         }  
  91.   
  92.         scanf("%d",&m);  
  93.   
  94.         while(m--){  
  95.             int a,b;  
  96.             scanf("%d%d",&a,&b);  
  97.   
  98.             map[a][b] = map[b][a] = getDistance(points[a],points[b]);  
  99.         }  
  100.   
  101.         int start,end;  
  102.         scanf("%d%d",&start,&end);  
  103.   
  104.         spfa(start);  
  105.   
  106.         printf("%.2lf\n",dist[end]);  
  107.     }  
  108. }  




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

[cpp]  view plain  copy
  1. /* 
  2.  * NEFU_208.cpp 
  3.  * 
  4.  *  Created on: 2014年5月27日 
  5.  *      Author: pc 
  6.  */  
  7.   
  8. #include <iostream>  
  9. #include <cstdio>  
  10. #include <cmath>  
  11.   
  12. using namespace std;  
  13.   
  14. const int maxn = 105;  
  15. const int inf = 10005;  
  16. //const int inf = INT_MAX; //注意不要轻易使用INT_MAX.如果这里使用了INT_MAX,那么如果2个inf相加的话,那么久整数溢出了...  
  17.   
  18. int n;  
  19. int map[maxn][maxn];  
  20.   
  21.   
  22. void initial(){  
  23.     int i;  
  24.     int j;  
  25.     for(i = 0 ; i < n ; ++i){  
  26.         for(j = 0 ; j < n ; ++j){  
  27.             if(i == j){  
  28.                 map[i][j] = 0;  
  29.             }else{  
  30.                 map[i][j] = inf;  
  31.             }  
  32.         }  
  33.     }  
  34. }  
  35.   
  36.   
  37. void floyd(){  
  38.     int i;  
  39.     int j;  
  40.   
  41.     int k;  
  42.     for( k = 0 ; k < n ; ++k){  
  43.         for(i = 0 ; i < n ; ++i){  
  44.             for(j = 0 ; j < n ; ++j){  
  45.                 if(map[i][j] > map[i][k] + map[k][j]){  
  46.                     map[i][j] = map[i][k] + map[k][j];  
  47.                 }  
  48.             }  
  49.         }  
  50.     }  
  51. }  
  52.   
  53. void printfMap(){  
  54.     int i;  
  55.     int j;  
  56.     for(i = 0 ; i < n ; ++i){  
  57.         for(j = 0 ; j < n ; ++j){  
  58.             printf("%d " ,map[i][j]);  
  59.         }  
  60.   
  61.         printf("\n");  
  62.     }  
  63. }  
  64.   
  65. int main(){  
  66.     int m;  
  67.     while(scanf("%d%d",&n,&m)!=EOF){  
  68.   
  69.         initial();  
  70.   
  71.         int i;  
  72.         for(i = 1 ; i <= m ; ++i){  
  73.             int a,b,c;  
  74.             scanf("%d%d%d",&a,&b,&c);  
  75.   
  76.             if(c < map[a][b]){//用来解决两个点之间可能有多条道路的问题  
  77.                 map[a][b] = map[b][a] = c;  
  78.             }  
  79.         }  
  80.   
  81.   
  82.         floyd();  
  83.   
  84.   
  85.         int start,end;  
  86.   
  87.         scanf("%d%d",&start,&end);  
  88.   
  89.         if(map[start][end] == inf){  
  90.             printf("-1\n");  
  91.         }else{  
  92.             printf("%d\n",map[start][end]);  
  93.         }  
  94.     }  
  95.   
  96.     return 0;  
  97. }  



2、dijkstra

[cpp]  view plain  copy
  1. /* 
  2.  * NEFU_208.cpp 
  3.  * 
  4.  *  Created on: 2014年5月27日 
  5.  *      Author: pc 
  6.  */  
  7.   
  8.   
  9. #include <iostream>  
  10. #include <cstdio>  
  11.   
  12. using namespace std;  
  13.   
  14. const int maxn = 105;  
  15. const int inf = 10005;  
  16.   
  17. int n;  
  18.   
  19. int s[maxn];  
  20. int dis[maxn];  
  21. int map[maxn][maxn];  
  22.   
  23. int target;  
  24.   
  25. int dijkstra(int v){  
  26.   
  27.     int i;  
  28.     for(i = 0 ; i < n ; ++i){  
  29.         s[i] = 0;  
  30.         dis[i] = map[v][i];  
  31.     }  
  32.   
  33.     for(i = 0 ; i < n-1 ; ++i){//这里的意思实际上是将剩下的n-1个点全部放到S集合中  
  34.         int min = inf;  
  35.         int pos;  
  36.   
  37.         int j;  
  38.         for(j = 0 ; j < n ; ++j){//寻找最短路径点  
  39.             if(!s[j] && dis[j] < min){  
  40.                 min = dis[j];  
  41.                 pos = j;  
  42.             }  
  43.         }  
  44.   
  45.         s[pos] = 1;  
  46.   
  47.         for(j = 0 ; j < n ; ++j){  
  48.             if(!s[j] && dis[j] > dis[pos] + map[pos][j]){  
  49.                 dis[j] = dis[pos] + map[pos][j];  
  50.             }  
  51.         }  
  52.     }  
  53.   
  54.     return dis[target];  
  55. }  
  56.   
  57.   
  58. int main(){  
  59.     int m;  
  60.     while(scanf("%d%d",&n,&m)!=EOF){  
  61.         int i;  
  62.         int j;  
  63.         for(i = 0 ; i < n ; ++i){  
  64.             for(j = 0 ; j < n ; ++j){  
  65.                 if(i == j){  
  66.                     map[i][j] = 0;  
  67.                 }else{  
  68.                     map[i][j] = inf;  
  69.                 }  
  70.             }  
  71.         }  
  72.   
  73.         for(i = 1 ; i <= m ; ++i){  
  74.             int a,b,c;  
  75.             scanf("%d%d%d",&a,&b,&c);  
  76.   
  77.             if(map[a][b] > c){  
  78.                 map[a][b] = map[b][a] = c;  
  79.             }  
  80.         }  
  81.   
  82.         int start,end;  
  83.         scanf("%d%d",&start,&end);  
  84.   
  85.         target = end;  
  86.         int result = dijkstra(start);  
  87.   
  88.         if(result == inf){  
  89.             printf("-1\n");  
  90.         }else{  
  91.             printf("%d\n",result);  
  92.         }  
  93.     }  
  94.   
  95.     return 0;  
  96. }  



3、spfa算法

[cpp]  view plain  copy
  1. /* 
  2.  * NEFU208.cpp 
  3.  * 
  4.  *  Created on: 2015年3月26日 
  5.  *      Author: Administrator 
  6.  */  
  7. #include <iostream>  
  8. #include <cstring>  
  9. #include <queue>  
  10. using namespace std;  
  11.   
  12. const int N = 105;  
  13. const int INF = 99999999;  
  14.   
  15. int map[N][N], dist[N];  
  16. bool visit[N];  
  17. int n, m;  
  18.   
  19. void init() {//初始化  
  20.     int i, j;  
  21.     for (i = 0; i < N; i++) {  
  22.         for (j = 0; j < N; j++) {  
  23.             if (i == j) {  
  24.                 map[i][j] = 0;  
  25.             } else {  
  26.                 map[i][j] = map[j][i] = INF;  
  27.             }  
  28.         }  
  29.     }  
  30. }  
  31.   
  32. /** 
  33.  * SPFA算法. 
  34.  * 使用spfa算法来求单元最短路径 
  35.  * 参数说明: 
  36.  * start:起点 
  37.  */  
  38. void spfa(int start) {  
  39.     queue<int> Q;  
  40.   
  41.     int i, now;  
  42.     memset(visit, falsesizeof(visit));  
  43.     for (i = 0; i < n; i++){  
  44.         dist[i] = INF;  
  45.     }  
  46.   
  47.     dist[start] = 0;  
  48.     Q.push(start);  
  49.     visit[start] = true;  
  50.     while (!Q.empty()) {  
  51.         now = Q.front();  
  52.         Q.pop();  
  53.         visit[now] = false;  
  54.         for (i = 0; i < n; i++) {//需要注意一下的是,这道题顶点的序号是从0开始的,到n-1.之前的题目都是1~n  
  55.             if (dist[i] > dist[now] + map[now][i]) {  
  56.                 dist[i] = dist[now] + map[now][i];  
  57.                 if (visit[i] == 0) {  
  58.                     Q.push(i);  
  59.                     visit[i] = true;  
  60.                 }  
  61.             }  
  62.         }  
  63.     }  
  64. }  
  65.   
  66.   
  67. int main(){  
  68.     while(scanf("%d%d",&n,&m)!=EOF){  
  69.         init();  
  70.   
  71.         while(m--){  
  72.             int a,b,c;  
  73.             scanf("%d%d%d",&a,&b,&c);  
  74.   
  75.   
  76.             if(map[a][b] > c){  
  77.                 map[a][b] = map[b][a] = c;  
  78.             }  
  79.         }  
  80.   
  81.         int start,end;  
  82.         scanf("%d%d",&start,&end);  
  83.   
  84.   
  85.         spfa(start);  
  86.   
  87.         if(dist[end] == INF){  
  88.             printf("-1\n");  
  89.         }else{  
  90.             printf("%d\n",dist[end]);  
  91.         }  
  92.     }  
  93.   
  94.     return 0;  
  95. }  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值