以下转自https://blog.csdn.net/weixin_42060896/article/details/82216379

例题:HDU 2544

最短路
Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 89730    Accepted Submission(s): 38892

Problem Description
在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?

Input
输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。
输入保证至少存在1条商店到赛场的路线。

Output
对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间

Sample Input
2 1
1 2 3
3 3
1 2 5
2 3 5
3 1 2
0 0

Sample Output
3
2

1),深度或广度优先搜索算法(解决单源最短路径)

从起始结点开始访问所有的深度遍历路径或广度优先路径,则到达终点结点的路径有多条,取其中路径权值最短的一条则为最短路径。
给定一个带权有向图G=(V,E),其中每条边的权是一个实数。另外,还给定V中的一个顶点,称为
源。
现在要计算从源到其他所有各顶点的最短路径长度。这里的长度就是指路上各边权之和。这个问题通
常称为单源最短路径 [1] 问题。
从起始结点开始访问所有的深度遍历路径或广度优先路径,则到达终点结点的路径有多条,取其中路
径权值最短的一条则为最短路径

下面是核心代码:

 1 //题意:求1->n的最短路径
 2 #include<iostream>
 3 #include<string.h>
 4 #define inf 99999999
 5 using namespace std;
 6 int dis[111][111];
 7 bool vis[111];
 8 int n,cnt;//n为节点数,cnt为最短长度
 9 void init(int x){
10          for(int i=0;i<=n;i++){
11                   for(int j=0;j<=n;j++)
12                            dis[i][j]=inf;
13                   dis[i][i]=0;
14                   vis[i]=0;
15          }
16 }
17 void dfs(int st,int dst)
18 {
19          if(dst>cnt)return ;//距离大于最短路径,无需遍历
20          if(st==n){//到达终点
21                   cnt=cnt>dst?dst:cnt;
22                   return;
23          }
24          for(int i=1;i<=n;i++)
25          {
26                   if(!vis[i]&&dis[st][i]!=inf&&dis[st][i]){
27                            vis[i]=1;
28                            dfs(i,dst+dis[st][i]);
29                            vis[i]=0;
30                   }
31          }
32 }
33 int main()
34 {
35          int m;
36          while(~scanf("%d%d",&n,&m)&&n&&m)
37          {
38                   int x,y,len;
39                   cnt=inf;
40                   init(n);
41                   while(m--){
42                            scanf("%d%d%d",&x,&y,&len);
43                            dis[x][y]=min(dis[x][y],len);//两点之间距离重复输入取小距离
44                            dis[y][x]=dis[x][y];
45                   }
46                   vis[1]=1;
47                   dfs(1,0);
48                   printf("%d\n",cnt);
49          }
50          return 0;
51 }
52 Sample Input 2
53 5 14
54 2 2 262
55 5 3 403
56 4 2 456
57 1 5 289
58 3 1 1000
59 2 4 217
60 2 5 536
61 2 5 415
62 2 4 880
63 3 1 179
64 3 4 972
65 5 3 2
66 1 3 491
67 4 1 872
68 0 0
69 Sample Output 2
70 181

2),弗洛伊德算法(解决多源最短路径):时间复杂度O(n^3),空间复杂度O(n^2)

基本思想:最开始只允许经过1号顶点进行中转,接下来只允许经过1号和2号顶点进行中转......允许经过1~n号所有顶点进行中转,来不断动态更新任意两点之间的最短路程。即求从i号顶点到j号顶点只经过前k号点的最短路程。

 1 //题意:求1->n的最短路径
 2 #include<iostream>
 3 #include<string.h>
 4 #define inf 99999999
 5 using namespace std;
 6 int n,dis[111][111];
 7 void init(){
 8          for(int i=0;i<=n;i++){
 9                   for(int j=0;j<=n;j++)
10                            dis[i][j]=inf;
11                   dis[i][i]=0;
12          }
13 }
14 int main()
15 {
16          int m;
17          while(~scanf("%d%d",&n,&m)&&n&&m)
18          {
19                   init();
20                   while(m--){
21                            int x,y,len;
22                            scanf("%d%d%d",&x,&y,&len);
23                            dis[x][y]=min(dis[x][y],len);
24                            dis[y][x]=dis[x][y];
25                   }
26                   for(int k=1;k<=n;k++)//要经过的点
27                            for(int i=1;i<=n;i++)
28                                     for(int j=1;j<=n;j++)
29                                              dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
30                   printf("%d\n",dis[1][n]);//可以选任意两点之间的距离
31          }
32          return 0;
33 }
34 Sample Input 2
35 5 14
36 2 2 262
37 5 3 403
38 4 2 456
39 1 5 289
40 3 1 1000
41 2 4 217
42 2 5 536
43 2 5 415
44 2 4 880
45 3 1 179
46 3 4 972
47 5 3 2
48 1 3 491
49 4 1 872
50 0 0
51 Sample Output 2
52 181

3),迪杰斯特拉算法(解决单源最短路径)

基本思想:每次找到离源点(如1号结点)最近的一个顶点,然后以该顶点为中心进行扩展,最终得到源点到其余所有点的最短路径。

基本步骤:1.开容器v,储存子节点、距离、花费;2、开数组dis记录起始点到各点距离;3、进行n-1次松弛操作(先找出未标记点中离起始点最近的点,标记该点,然后求出该点子节点到起始点的最短距离(优先)与最短花费);4、输出到终点的最短距离与花费;

 1 //题意:求两点之间最短路径
 2 #include<iostream>
 3 #include<string.h>
 4 #include<vector>
 5 #include<algorithm>
 6 #define N 999999999
 7 using namespace std;
 8 struct node{
 9          int er,len,cost;
10 };
11 vector<node>v[1111];
12 int main()
13 {
14          int n,m;
15          while(~scanf("%d%d",&n,&m)&&n&&m)
16          {
17                   int dis[1111],spend[1111];
18                   bool vis[1111];
19                   node tmp;
20                   int x,y;
21                   for(int i=0;i<1111;i++)
22                            v[i].clear();
23                   while(m--){
24                            scanf("%d%d%d%d",&x,&y,&tmp.len,&tmp.cost);
25                            tmp.er=x;
26                            v[y].push_back(tmp);
27                            tmp.er=y;
28                            v[x].push_back(tmp);
29                   }
30                   scanf("%d%d",&x,&y);//起点和终点
31                   for(int i=1;i<=n;i++){
32                            vis[i]=0;
33                            dis[i]=spend[i]=N;
34                   }
35                   for(int i=0;i<v[x].size();i++){
36                            dis[v[x][i].er]=v[x][i].len;
37                            spend[v[x][i].er]=v[x][i].cost;
38                   }
39                   vis[x]=1;
40                   for(int k=1;k<=n-1;k++)
41                   {
42                            int id,mi=N;
43                            for(int i=1;i<=n;i++){
44                                     if(!vis[i]&&dis[i]<mi){//查询并记录离x最近的点
45                                              id=i;mi=dis[i];
46                                     }
47                            }
48                            vis[id]=1;//标记过的点已经是最短
49                            for(int i=0;i<v[id].size();i++)
50                            {
51                                     int vv=v[id][i].er;
52                                     if(!vis[vv]&&dis[vv]>dis[id]+v[id][i].len)//未标记、直接距离大于通过id点的距离
53                                              dis[vv]=dis[id]+v[id][i].len,
54                                              spend[vv]=spend[id]+v[id][i].cost;
55                                     else if(!vis[vv]&&dis[vv]==dis[id]+v[id][i].len&&spend[vv]>spend[vv]+v[id][i].cost)//未标记、距离相等找花费更小的
56                                              spend[vv]=spend[id]+v[id][i].cost;
57                            }
58                   }
59                   printf("%d %d\n",dis[y],spend[y]);
60          }
61          return 0;
62 }
63 /*
64 3 2
65 1 2 5 6
66 2 3 4 5
67 1 3
68 3 2
69 1 3 5 6
70 2 1 3 5
71 3 2
72 9 11
73 8 11
74 */

4),Bellman-Ford算法(解决负权边,解决单源最短路径,前几种方法不能求含负权边的图)::时间复杂度O(nm),空间复杂度O(m)

主要思想:对所有的边进行n-1轮松弛操作,因为在一个含有n个顶点的图中,任意两点之间的最短路径最多包含n-1边。换句话说,第1轮在对所有的边进行松弛后,得到的是从1号顶点只能经过一条边到达其余各定点的最短路径长度。第2轮在对所有的边进行松弛后,得到的是从1号顶点只能经过两条边到达其余各定点的最短路径长度,......
以下是图示:

此外,Bellman_Ford还可以检测一个图是否含有负权回路:POJ1860

 1 /*
 2 题意:有多种汇币,汇币之间可以交换,这需要手续费,当你用100A币
 3 交换B币时,A到B的汇率是29.75,手续费是0.39,那么你可以得到
 4 (100 - 0.39) * 29.75 = 2963.3975 B币。问s币的金额经过交换最终
 5 得到的s币金额数能否增加
 6 货币的交换是可以重复多次的,所以我们需要找出是否存在
 7 正权回路,且最后得到的s金额是增加的
 8 怎么找正权回路呢?(正权回路:在这一回路上,顶点的权值能不断增加即能一直进行松弛)
 9 分析:
10 反向利用Bellman-Ford算法
11 单源最短路径算法,因为题目可能存在负边,所以用Bellman Ford算法,
12 原始Bellman Ford可以用来求负环,这题需要改进一下用来求正环
13 一种货币就是图上的一个点
14 一个“兑换点”就是图上两种货币之间的一个兑换环,相当于“兑换方式”M的个数,是双边
15 唯一值得注意的是权值,当拥有货币A的数量为V时,A到A的权值为K,即没有兑换
16 而A到B的权值为(V-Cab)*Rab
17 本题是“求最大路径”,之所以被归类为“求最小路径”是因为本题题恰恰
18 与bellman-Ford算法的松弛条件相反,求的是能无限松弛的最大正权路径,
19 但是依然能够利用bellman-Ford的思想去解题。
20 因此初始化d(S)=V   而源点到其他店的距离(权值)初始化为无穷小(0),
21 当s到其他某点的距离能不断变大时,说明存在最大路径
22 */
23 #include<iostream>
24 #include<string.h>
25 #include<algorithm>
26 using namespace std;
27 struct node
28 {
29          int x,y;
30          double r,c;
31 }num[222];
32 int n,m,s,ans;
33 double v;
34 void add(int x,int y,double r,double c)
35 {
36          num[ans].x=x;
37          num[ans].y=y;
38          num[ans].r=r;
39          num[ans].c=c;
40          ans++;
41 }
42 bool bellon()
43 {
44          double dis[111];
45          for(int i=0;i<=n;i++)
46                   dis[i]=0;
47          dis[s]=v;
48          for(int j=1;j<n;j++)
49          {
50                   bool flag=0;
51                   for(int i=0;i<ans;i++){
52                            if(dis[num[i].y]<(dis[num[i].x]-num[i].c)*num[i].r)
53                                     dis[num[i].y]=(dis[num[i].x]-num[i].c)*num[i].r,flag=1;
54                   }
55                   if(!flag)
56                            return 0;
57          }
58          for(int i=0;i<ans;i++)
59                   if(dis[num[i].y]<(dis[num[i].x]-num[i].c)*num[i].r)
60                            return 1;
61          return 0;
62 }
63 int main()
64 {
65          int a,b;
66          ans=0;
67          double ra,rb,ca,cb;
68          scanf("%d%d%d%lf",&n,&m,&s,&v);
69          while(m--)
70          {
71                   scanf("%d%d%lf%lf%lf%lf",&a,&b,&ra,&ca,&rb,&cb);
72                   add(a,b,ra,ca);
73                   add(b,a,rb,cb);
74          }
75          if(bellon())
76                   printf("YES\n");
77          else
78                   printf("NO\n");
79          return 0;
80 }

转载于:https://www.cnblogs.com/hualian/p/11171370.html

【常用算法总结——最短路径四种方法】相关推荐

  1. 求解最大公约数算法(包含四种方法)

    方法一: #include<iostream> #include<algorithm> #include<cstdio> #include<cmath> ...

  2. Hash算法解决冲突的四种方法

    Hash算法解决冲突的四种方法 参考文章: (1)Hash算法解决冲突的四种方法 (2)https://www.cnblogs.com/lyfstorm/p/11044468.html 备忘一下.

  3. 清除浮动最常用的四种方法

    1.为什么要清除浮动 开发过程中,浮动是需要掌握的一个技能,页面布局当中,在无法确定子元素的高度(height)时,我们无法给父级标签一个固定的高度(height),我们想要的是,由子元素的高度去控制 ...

  4. 创建JSONArray的常用四种方法

     创建JSONArray的常用四种方法 1.从头或者从零开始,创建一个JSONArray(Creating a JSONArray from scratch) 实例1: Java代码  JSONA ...

  5. PHP取整数函数常用的四种方法

    PHP取整数函数常用的四种方法: 1.直接取整,舍弃小数,保留整数:intval():  2.四舍五入取整:round():  3.向上取整,有小数就加1:ceil():  4.向下取整:floor( ...

  6. 使用Spring Security3的四种方法概述

    使用Spring Security3的四种方法概述 那么在Spring Security3的使用中,有4种方法: 一种是全部利用配置文件,将用户.权限.资源(url)硬编码在xml文件中,已经实现过, ...

  7. 用MATLAB结合四种方法搜寻罗马尼亚度假问题

    选修了cs的AI课,开始有点不适应,只能用matlab硬着头皮上了,不过matlab代码全网仅此一份,倒有点小自豪. 一.练习题目 分别用宽度优先.深度优先.贪婪算法和 A*算法求解"罗马利 ...

  8. C语言四种方法求最大公约数

    一.实验要求 运行最大公约数的常用算法,并进行程序的调试与测试,要求程序设计风格良好,并添加异常处理模块. 二.实验方法(四种) 1.辗转相除法(欧几里德法) C语言中用于计算两个正整数a,b的最大公 ...

  9. java indexof 子字符串_Java中字符串中子串的查找共有四种方法(indexof())

    Java中字符串中子串的查找共有四种方法(indexof()) Java中字符串中子串的查找共有四种方法,如下: 1.int indexOf(String str) :返回第一次出现的指定子字符串在此 ...

最新文章

  1. CloudStack管理员文档 - 虚拟机
  2. Service 和 doGet 和 doPost 方法的区别
  3. 智能风控平台核心之风控决策引擎(二)
  4. 在日期格式化的时候提示错误:Tostring没有采用一个参数的重载
  5. 电子书下载:Illustrated C# 2012 4th
  6. java 输入流关闭顺序_Java IO流中先关闭输出流还是先关闭输入流?为什么?
  7. LeetCode 1089. 复写零
  8. 编程语言分类 -- 强类型与弱类型、动态类型与静态类型
  9. (17)FPGA速度和面积互换原则
  10. c++ opencv 识别车牌_小强学Python+OpenCV之-1.0开篇
  11. ulimit限制 新系统_graylog日志分析系统上手教程
  12. 一个优秀数据分析师的准则
  13. 微信小程序实现下拉刷新
  14. SSD硬盘的数据恢复
  15. linux2t硬盘格式化时间,linux下大于2T硬盘格式化方法
  16. SAP项目上的疑难杂症-(制品区分)如何处理?
  17. 什么是机器学习(漫画版)
  18. Syn-QG: Syntactic and Shallow S emantic Rules for Question Generation阅读笔记
  19. 夜明け前より瑠璃色な 攻略
  20. JavaSE——Day1——计算机基础知识、Java语言基础、JRE与JDK

热门文章

  1. ReactiveCocoa个人记录
  2. freebsd下vi的使用
  3. 蒙特卡洛算法及其实现
  4. Tomcat服务器 Varnish代理服务器
  5. ASP保存远程图片到本地 同时取得第一张图片
  6. windows 命令行
  7. 写的很好!细数 Java 线程池的原理
  8. 微软研究员:fork() 已落后,需要淘汰
  9. 小米自动化运维平台演进设计思路
  10. 谈谈怎么做【服务隔离】