最短路径算法总结

一、目的;

求源点到其他点之间的最短距离;

二、floyd算法;

(1)     假设起点为A,终点为B,则A到B的距离要么是A直接到B,要么A经过其他节点到B,假设我们经过的节点为K,则最短路为min(dist[A][B],dist[A][K]+dist[K][B])每次更新即可;

For (i=1;i<=n;i++)

For (j=1;j<=n;j++)

For(k=1;k<=n;k++)

Dist[i][j]=min(dist[i][k]+dist[k][j],dist[i][j]);

(2) 以上代码看起来似乎没错,但是假设图中有环的话,就会出现错误,比如A到B为9,A 到C为2 ,C到D为2,D到B为2,当i等于A,j等于B时,AB之间因为存在两个节点,所以并没有更新,即会出现错误。

我们可以这样来更新,根据中心点,来更新这个点两端的距离,比如C为中心点,则更新AD,然后D为中心点,更新AB,CB,B为中心点,更新AD,AC,以此类推。

For(k=1;k<=n;k++)

For(i=1;i<=n;i++)

For(j=1;j<=n;j++)

Dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);

(3)路径保存问题;

我们可以设p[i][j]为路径ij中,j前面的那个节点;

Void savePath(){

For (i=1;i<=n;i++)

For(j=1;j<=n;j++)

If(map[i][j]==MAX){

P[i][j]=-1;

}else p[i][j]=i;

For(k=1;k<=n;k++)

For (i=1;i<=n;i++)

For (j=1;j<=n;j++)

If(dist[i][j]>dist[i][k]+dist[k][j]){

Dist[i][j]=dist[i][k]+dist[k][j];

P[i][j]=p[k][j];

}

I=from;j=to;

Printf(“%d”,j);

While(p[i][j]!=from){

Printf(“%d”,p[i][j]);

J=p[i][j];

}

}

三、dijkstra算法

(1)   本算法是计算单源最短路的算法,即一个原点到其他节点最短路的算法,原理为,

假设已经计算出最短路的节点集合为S,没计算出来的为V,最开始S只有一个源点,然后d[i]代表s到i的最短距离,首先我们找出d中的最小值的节点t,然后将他加入S。

为什么这个时候d[t]一定是最短路径呢?

因为假设t不是最短路,那么一定存在另外的一条路更小,假设中间节点为k则最短路一定为d[k]+map[k][t];而d[t]为最小值与题意不符,故d[t]一定为最短路径。

(2)

void init(){

int i,j;

scanf("%d%d",&n,&m);

for (i=1;i<=n;i++)

for (j=1;j<=n;j++)

map[i][j]=MAX;

for (i=1;i<=m;i++)

{

int k,l,g;

scanf("%d%d%d",&k,&l,&g);

map[k][l]=g;

map[l][k]=g;

}

}

void dijkstra()

{

int s,i,j;

int v[10]={0};

scanf("%d",&s);

for (i=1;i<=n;i++)

d[i]=map[s][i];

v[s]=1;

for (i=1;i<=n-1;i++)

{

int min=MAX,minj;

for(j=1;j<=n;j++)

if(!v[j]&&min>d[j])

{

min=d[j];

minj=j;

}

v[minj]=1;

for (j=1;j<=n;j++)

if(!v[j]&&d[j]>d[minj]+map[minj][j])

{

d[j]=d[minj]+map[minj][j];

}

}

for (i=1;i<=n;i++)

printf("%d %d\n",i,d[i]);

}

(2)这个算法不能用于存在负权值的情况。

如1->2 6

1->3 5

2 ->3 -2

此时算法会出错。

四、Bellman-ford算法

(1)这个算法可以用于处理负权值边,原理:是利用每条边进行松弛操作,个人认为就是用每一条边刷新一次最短路。

(2)我们可以用d数组来记录最短路径长度,初始化为max,然后原点到原点的最短路为零,然后遍历n-1次,每次遍历利用所有的边来刷新最短路,要遍历n-1次的原因是因为最短路一定不包含环,假如包含正值环的话,去掉这个环,结果显然更优,因此最短路径中一定包含n-1条边,而我们每次刷新至少要刷新一条边,假设没有刷新了说明我们最短路已经找到了。

(3)void bellman_ford()

{

int s,i,j;

scanf("%d",&s);

for (i=1;i<=n;i++)

d[i]=MAX;

d[s]=0;

for (i=1;i<=n-1;i++)

for (j=1;j<=m;j++)

if(d[edge[j].v]>d[edge[j].u]+edge[j].value)

{

d[edge[j].v]=d[edge[j].u]+edge[j].value;

}

int flag=0;

//判断是否存在权值为负的环

for (j=1;j<=m*2;j++)

if(d[edge[j].v]+d[edge[j].u]+edge[j].value<0)

{

flag=1;

}

if(flag)printf("存在负环\n");

else printf("不存在负环\n");

for (i=1;i<=n;i++)

printf("%d %d\n",i,d[i]);

}

四、spfa算法

(1)     算法是对bellman-ford算法的优化

(2)     将我们每次优化后的节点放入队列,根据队列里面的节点进行优化,减少了比较次数,同时减小了时间复杂度。

(3)     初始化我们可以定义一个数组d表示最短距离,然后c数组代表每个点进入队列的次数,当c超过n次的时候一定存在负环,要大于n而不是n-1次的原因,我认为应该防止只有一个点的情况。

(4)     Spfa-bfs算法;

采用邻接表储存数据,

#include<stdio.h>

#define MAX 9999

int b[10][10]={0},w[10][10]={0};

int n,m;

int d[10];

void init()

{

int i,j;

scanf("%d%d",&n,&m);

for (i=1;i<=m;i++)

{

int k,l,g;

scanf("%d%d%d",&k,&l,&g);

b[k][0]++;

b[k][b[k][0]]=l;

w[k][b[k][0]]=g;

}

}

void spfa_bfs()

{

int q[100];

int h,t,i,j;

h=1;t=1;

int s;

int flag=0;

int v[10]={0};

int c[10]={0};

scanf("%d",&s);

for (i=1;i<=n;i++) d[i]=MAX;

d[s]=0;c[s]=1;q[1]=s;v[s]=1;

while(h<=t)

{

int u=q[h];v[u]=0;

for (j=1;j<=b[u][0];j++)

{

int y=b[u][j];

if(d[y]>d[u]+w[u][j])

{

d[y]=d[u]+w[u][j];

if(!v[y]){

t++;

q[t]=y;

c[y]++;

v[y]=1;

if(c[y]>n){

flag=1;

break;

}

}

}

}

if(flag) break;

h++;

}

for(i=1;i<=n;i++)

printf("%d %d\n",i,d[i]);

if(flag) printf("There exist fuhuan\n");

else printf("There not exist fuhuan\n");

}

int main()

{

init();

spfa_bfs();

return 0;

}

(5) 当我们用队列宽搜来判断是否有负环时,会让一个负环重复很多次才会判断出来,浪费了时间,而我们用深搜可以直接判断假设有负环我们会回到访问过的节点,并且会执行松弛操作,而正环则不会进行松弛操作。

int spfa_dfs(int u)

{

vi[u]=1;

int j;

for (j=1;j<=b[u][0];j++)

{

int y=b[u][j];

if(d[y]>d[u]+w[u][j]){

d[y]=d[u]+w[u][j];

if(!vi[y]){

if(spfa_dfs(y)){

return 1;

}

}else

return 1;

//当访问过这个节点并且沿着这条路又可以对当前节点进行松弛操作时,说明存在负环

}

}

vi[u]=0;

return 0;

}

(6)关于最短路径的记录问题,直接定义一个数组pre记录前驱,在进行松弛操作时更改即可。

时间: 2024-12-05 17:33:56

最短路径算法总结的相关文章

最短路径算法专题1----弗洛伊德

由于最短路径算法我认为比较重要,所以分成几个专题来慢慢细化去磨它,不能一口气吃个胖子嘛. 首先在说算法之前,先说清楚什么叫做最短路径. 题目一般会给你一张图,然后告诉你很多地方,然后告诉你各个地方之间的路程有多远,要你求出,两点间的最短距离,注意,题目给出的两点间的距离未必是最短的,可能通过第三个点转换之后达到更短.实际其实也是这样的,有时候两个地方并没有直线的道路只有曲线的绕路. 算法的思路: 1.用二维数组列出所有的距离,达到不了的用最大距离表示,如9999999 2.循环数组上面的每一个点

图论之最短路径算法

简介: 求最短路径算法中最具代表性的是Dijkstra算法. Dijkstra算法的思想是基于贪心策略的. 概述其过程是通过设置顶点集合S并不断地做贪心选择来扩充集合. 贪心选择的标准是每次都选择从源节点到该节点的路径长度最短. 难点: 网络上博客中大多数人写的最短路径算法大多都是只能寻找到最短的一条路径. 但是很多时候可能存在并列最短的路径,需要找出所有同时最短的路径. 在这里我给大家分享一个时间复杂度大概是O(n2)的算法,求并列最短路径算法. 求出一条最短路径的算法步骤如下: 假设G={V

最短路径算法

最短路径-Dijkstra算法和Floyd算法 1.Dijkstra算法 1.1.定义概览Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等.注意该算法要求图中不存在负权边. 问题描述:在无向图 G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点

最短路径算法整理(二)

本文是最短路径算法整理的第二篇,想阅读第一篇的朋友能够点击下面链接: http://blog.csdn.net/hjd_love_zzt/article/details/26739593 这一篇博客继续以一些OJ上的题目为载体,整理一下最短路径算法.会陆续的更新... 1.HDU 2544 题目与分析:这道题抽象一下,还是:"求a到b的最短路径"..所须要的基本条件是:点数.边数.起点.终点 下面给出floyd.dijkstra.bellmanford三种最短路径算法关于这道题的解法:

最短路径算法学习总结

Dijkstra最短路径算法: dijkstra 算法的优点在于可以求出从一点到所有其他点的最短距离: input: 5 71 2 101 3 201 5 302 5 102 3 54 5 204 3 30 output: 0 10 15 40 20//这是求的在这颗树中,1到所有点的最短距离 1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 const int N=1100; 5 const int

无向图的最短路径算法JAVA实现(转)

一,问题描述 给出一个无向图,指定无向图中某个顶点作为源点.求出图中所有顶点到源点的最短路径. 无向图的最短路径其实是源点到该顶点的最少边的数目. 本文假设图的信息保存在文件中,通过读取文件来构造图.文件内容的格式参考这篇文章第一部分. 二,算法实现思路 无向图的最短路径实现相对于带权的有向图最短路径实现要简单得多. 源点的最短路径距离为0,从源点开始,采用广度优先的顺序,首先将与源点邻接的顶点的路径求出,然后再依次求解图中其他顶点的最短路径. 由于顶点的最短路径的求解顺序 是一个 广度优先的顺

最短路径算法-Dijkstra算法的应用之单词转换(词梯问题)

一,问题描述 在英文单词表中,有一些单词非常相似,它们可以通过只变换一个字符而得到另一个单词.比如:hive-->five:wine-->line:line-->nine:nine-->mine..... 那么,就存在这样一个问题:给定一个单词作为起始单词(相当于图的源点),给定另一个单词作为终点,求从起点单词经过的最少变换(每次变换只会变换一个字符),变成终点单词. 这个问题,其实就是最短路径问题. 由于最短路径问题中,求解源点到终点的最短路径与求解源点到图中所有顶点的最短路径复

几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较(转)

几大最短路径算法比较 几个最短路径算法的比较:Floyd        求多源.无负权边(此处错误?应该可以有负权边)的最短路.用矩阵记录图.时效性较差,时间复杂度O(V^3).       Floyd-Warshall算法(Floyd-Warshall algorithm)是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题. Floyd-Warshall算法的时间复杂度为O(N^3),空间复杂度为O(N^2). Floyd-Warshall的原理是动态规划:设Di,j

最短路径算法集锦

/* Name: 最短路径算法集锦 Copyright: Author: 巧若拙 Date: 12/11/14 15:32 Description: 列举了深度优先搜索的递归和非递归算法,Dijkstra最短路径算法, 基于Bellman-Fort最短路径算法的改进型广度优先搜索算法, Floyd-Warshall最短路径算法的原始版和变化版 本文是阅读<啊哈!算法>后的学习笔记,代码与教材中有些差异,若有错误请指正,谢谢! 测试数据: 5 7 0 3 2 0 4 9 4 2 1 4 1 3

(最短路径算法整理)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) {//遍历