【常用算法总结——最短路径四种方法】
以下转自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
【常用算法总结——最短路径四种方法】相关推荐
- 求解最大公约数算法(包含四种方法)
方法一: #include<iostream> #include<algorithm> #include<cstdio> #include<cmath> ...
- Hash算法解决冲突的四种方法
Hash算法解决冲突的四种方法 参考文章: (1)Hash算法解决冲突的四种方法 (2)https://www.cnblogs.com/lyfstorm/p/11044468.html 备忘一下.
- 清除浮动最常用的四种方法
1.为什么要清除浮动 开发过程中,浮动是需要掌握的一个技能,页面布局当中,在无法确定子元素的高度(height)时,我们无法给父级标签一个固定的高度(height),我们想要的是,由子元素的高度去控制 ...
- 创建JSONArray的常用四种方法
创建JSONArray的常用四种方法 1.从头或者从零开始,创建一个JSONArray(Creating a JSONArray from scratch) 实例1: Java代码 JSONA ...
- PHP取整数函数常用的四种方法
PHP取整数函数常用的四种方法: 1.直接取整,舍弃小数,保留整数:intval(): 2.四舍五入取整:round(): 3.向上取整,有小数就加1:ceil(): 4.向下取整:floor( ...
- 使用Spring Security3的四种方法概述
使用Spring Security3的四种方法概述 那么在Spring Security3的使用中,有4种方法: 一种是全部利用配置文件,将用户.权限.资源(url)硬编码在xml文件中,已经实现过, ...
- 用MATLAB结合四种方法搜寻罗马尼亚度假问题
选修了cs的AI课,开始有点不适应,只能用matlab硬着头皮上了,不过matlab代码全网仅此一份,倒有点小自豪. 一.练习题目 分别用宽度优先.深度优先.贪婪算法和 A*算法求解"罗马利 ...
- C语言四种方法求最大公约数
一.实验要求 运行最大公约数的常用算法,并进行程序的调试与测试,要求程序设计风格良好,并添加异常处理模块. 二.实验方法(四种) 1.辗转相除法(欧几里德法) C语言中用于计算两个正整数a,b的最大公 ...
- java indexof 子字符串_Java中字符串中子串的查找共有四种方法(indexof())
Java中字符串中子串的查找共有四种方法(indexof()) Java中字符串中子串的查找共有四种方法,如下: 1.int indexOf(String str) :返回第一次出现的指定子字符串在此 ...
最新文章
- CloudStack管理员文档 - 虚拟机
- Service 和 doGet 和 doPost 方法的区别
- 智能风控平台核心之风控决策引擎(二)
- 在日期格式化的时候提示错误:Tostring没有采用一个参数的重载
- 电子书下载:Illustrated C# 2012 4th
- java 输入流关闭顺序_Java IO流中先关闭输出流还是先关闭输入流?为什么?
- LeetCode 1089. 复写零
- 编程语言分类 -- 强类型与弱类型、动态类型与静态类型
- (17)FPGA速度和面积互换原则
- c++ opencv 识别车牌_小强学Python+OpenCV之-1.0开篇
- ulimit限制 新系统_graylog日志分析系统上手教程
- 一个优秀数据分析师的准则
- 微信小程序实现下拉刷新
- SSD硬盘的数据恢复
- linux2t硬盘格式化时间,linux下大于2T硬盘格式化方法
- SAP项目上的疑难杂症-(制品区分)如何处理?
- 什么是机器学习(漫画版)
- Syn-QG: Syntactic and Shallow S emantic Rules for Question Generation阅读笔记
- 夜明け前より瑠璃色な 攻略
- JavaSE——Day1——计算机基础知识、Java语言基础、JRE与JDK