Dijkstra算法和Floyed算法「建议收藏」

Dijkstra算法和Floyed算法「建议收藏」Dijkstra算法和Floyed算法最短路径:在非网图中,最短路径是指两顶点之间经历的边数最少的路径。在网图中,最短路径是指两顶点之间经历的边上权值之和最短的路径。最短路径问题:单源点到其他顶点的最短路径:Dijkstra方法,O(n2)按路径长度递增任意一对顶点之间的最短路径:Floyed方法,O(n3)Dijkstra算法:按路径长度递增1.设置一个集合S存放已经找到最短…

大家好,又见面了,我是你们的朋友全栈君。

Dijkstra算法和Floyed算法

最短路径:

非网图中,最短路径是指两顶点之间经历的边数最少的路径。
网图中,最短路径是指两顶点之间经历的边上权值之和最短的路径。

最短路径问题:

单源点到其他顶点的最短路径:
Dijkstra方法,O(n2)按路径长度递增
任意一对顶点之间的最短路径:
Floyed方法,O(n3)

Dijkstra算法:按路径长度递增

1.设置一个集合S存放已经找到最短路径的顶点,S的初始状态只包含源点v,
2.对vi∈V-S,假设从源点v到vi的有向边为最短路径(从v到其余顶点的最短路径的初值)。
3.以后每求得一条最短路径v, …, vk,就将vk加入集合S中,并将路径v, …, vk , vi与原来的假设相比较,取路径长度较小者为最短路径。
4.重复上述过程,直到集合V中全部顶点加入到集合S中。

路径长度最短的最短路径(即第一条最短路)的特点:
在这条路径上,必定只含一条边,并且这条边上的权值最小。

下一条路径长度次短的最短路径的特点:
(1)直接从源点到该点(只含一条边);
(2)从源点经过顶点v1(第一条最短路径所依附的顶点),再到达该顶点(由两条边组成)。

再下一条路径长度次短的最短路径的特点:
(1)直接从源点到该点(只含一条边);
(2)从源点经过顶点v1,再到达该顶点(由两条边组成);
(3)从源点经过顶点v2,再到达该顶点(两条条边);
(4)从源点经过顶点v1、v2,再到达该顶点(多条边)。

其余最短路径的特点:
(1)直接从源点到该点(只含一条边);
(2)从源点经过已求得最短路径的顶点(集合S中的顶点),再到达该顶点。

迪杰斯特拉算法的主要步骤:

(1) g为用邻接矩阵表示的带权图。
S←{v0} , dist[i]= g.arcs[v0][vi],path[i]=“v0vi”或“”;
将v0到其余顶点的路径长度初始化为权值;
(2) 选择vk,使得
dist[vk]=min(dist[i] | vi∈V-S)
vk为目前求得的下一条从v0出发的最短路径的终点。
将vk加入到S中
(3) 修改从v0出发到集合V-S上任一顶点vi的最短路径的长度。如果
dist[k]+ g.arcs[k][i]<dist[i]
则将dist[i]修改为
dist[k]+ g.arcs[k][i]
path[i]=path[k]+”vi”
(4) 重复(2)、(3) n-1次,即可按最短路径长度的递增顺序,逐个求出v0到图中其它每个顶点的最短路径。

const int MAX=1000;
void  Dijkstra(MGraph g, int v){
       for ( i =0; i<g.vexnum ; i++){
	 dist[i]=g.arcs[v][i];  
               if ( dist[i]!= MAX) 
                      path [i]=g.vertex[v]+g.vertex[i];
               else
                      path[i]=“”;
       }
       S[0]=g.vertex[v]; 
       num=1;  
       While (num<g.vextexNum){
    k=0;
    for(i=0;i<G.vertexNum;i++)
           if((dist[i]<dist[k])   k=i
    cout<<dist[k]<<path[k];
    s[num++]=G.vertex[k];                
    for(i=0;i<G.vertexNum;i++)
             if(dist[k]+g.arc[k][i]<dist[i] {
		 dist[i]=dist[k]+g.arc[k][i];
                       path[i]=path[k]+g.vertex[i];
               }
}
}

Floyed算法——基本思想:

设图g用邻接矩阵法表示, 求图g中任意一对顶点vi、 vj间的最短路径。
(-1) 将vi到vj 的最短的路径长度初始化为(vi,vj), 然后进行如下n次比较和修正:
(0) 在vi、vj间加入顶点v0,比较(vi, v0, vj)和(vi, vj)的路径的长度,取其中较短的路径作为vi到vj的且中间顶点号不大于0的最短路径。
(1) 在vi、vj间加入顶点v1,
得(vi, …,v1)和(v1, …,vj),其中:
(vi, …, v1)是vi到v1 的且中间顶点号不大于0的最短路径,
(v1, …, vj) 是v1到vj 的且中间顶点号不大于0的最短路径,
这两条路径在上一步中已求出。
将(vi, …, v1, …, vj)与上一步已求出的且vi到vj 中间顶点号不大于0的最短路径比较,取其中较短的路径作为vi到vj 的且中间顶点号不大于1的最短路径。
(2)在vi、vj间加入顶点v2,得
(vi, …, v2)和(v2, …, vj), 其中:
(vi, …, v2)是vi到v2 的且中间顶点号不大于1的最短路径,
(v2, …, vj) 是v2到vj 的且中间顶点号不大于1的最短路径,
这两条路径在上一步中已求出。
将(vi, …, v2, …, vj)与上一步已求出的且vi到vj 中间顶点号不大于1的最短路径比较, 取其中较短的路径作为vi到vj 的且中间顶点号不大于2的最短路径。

void Floyd(MGraph G)
{
  for (i=0; i<G.vertexNum; i++)        
     for (j=0; j<G.vertexNum; j++)
     {
        dist[i][j]=G.arc[i][j];
        if (dist[i][j]!=∞) 
             path[i][j]=G.vertex[i]+G.vertex[j];
        else path[i][j]=""; 
     }
          for (k=0; k<G.vertexNum; k++)         
      for (i=0; i<G.vertexNum; i++)       
         for (j=0; j<G.vertexNum; j++)
             if (dist[i][k]+dist[k][j]<dist[i][j]) {
                  dist[i][j]=dist[i][k]+dist[k][j];
                  path[i][j]=path[i][k]+path[k][j];
            }
}

完整代码(Dijkstra):

/*输入:
5 6
0
0 1 1
0 2 2
0 3 1
1 2 1
2 4 1
3 4 1 
或 
6 9
0
0 1 1
0 2 12
1 2 9
1 3 3
2 4 5
3 2 4
3 4 13
3 5 15
4 5 4
*/
#include <iostream>
#include <algorithm>
#include <stack>
using namespace std;
 
#define N 520
int edge[N][N],weight[N],disp[N];
 
bool visited[N] = {false};
const int inf = 999999;
 
int main(){
	int prev[N];//用来标注当前结点的上一个结点,以便输出两点间最短路线 
	
	fill(edge[0],edge[0] + N * N,inf);//注意这里要是N*N,要不然不是全部 
	fill(disp,disp + N,inf);
	
	
	int n,m;//对应城市数,城市之间连线数
	cin>>n>>m;
	
	int start_point;
	cin>>start_point;//输入起点城市 
	
	int a,b,c;
	for(int i=0;i < m;i++)
	{
		cin>>a>>b>>c;
		edge[a][b] = edge[b][a] = c; 	
	}
	
	for(int i=0;i<N;i++){
		prev[i] = i;//初始状态设每个点的前驱为自身
		edge[i][i] = 0;
	}
		
	
	disp[start_point] = 0;
	for(int i = 0;i < n;i++){
		int u = -1,min = inf;
		for(int j = 0;j < n;j++){
			if(visited[j] == false && disp[j] <= min)
			{
				u = j;
				min = disp[j];
			}
		}	
		
		if(u == -1)
			break;
		
		visited[u] = true;
		for(int v = 0;v < n;v++){
			if(visited[v] == false && edge[u][v] != inf)
			{
				if(disp[u] + edge[u][v] < disp[v]){
					disp[v] = disp[u] + edge[u][v];
					prev[v] = u;//prev保存当前结点的上一个节点,以便输出最短路线
					cout<<v<<" "<<prev[v]<<endl; 
				} 		
			}
		}		
	}
	
	//显示起点到各个点的最短路径	
	for (int i=0;i<n;i++)
	{
		cout<<"起点"<<start_point<<"到"<<i<<"的最短距离为: "<<disp[i]<<endl;
	}
	
	//显示起到到某个点的线路 
	int end_point;//终点
	cout<<"请输入终点:"; 
	cin>>end_point; 
	stack<int> myStack;
	
	int temp = end_point;
	myStack.push(end_point);//先加终点 
	while(start_point != temp){
		temp = prev[temp];
		myStack.push(temp);//注意这里是把当前点的上一个结点放进去,此时换成了temp 
	}
	
	cout<<"起点"<<start_point<<"到"<<end_point<<"的最短路线为: ";
	while(!myStack.empty()){
		cout<<myStack.top()<<" ";
		myStack.pop(); 
	}
	
	return 0;
}

完整代码(Floyed):

#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
const int MaxSize=100;
 
class  MGraph
{
public:
    MGraph(char a[],int n,int e);
    ~MGraph(){}
    friend void Floyd(MGraph G);
private:
    char   vertex[MaxSize];             //节点数组
    int  arc[MaxSize][MaxSize];      //矩阵
    int vertexNum,arcNum;            //节点数与边数
    int visited[MaxSize];            //访问记录
};
 
MGraph::MGraph(char a[],int n,int e)
{
    int i,j,k;
    vertexNum=n;
    arcNum=e;
    for(i=0;i<vertexNum;i++)
    {
        vertex[i]=a[i];
    }
 
    for(i=0;i<vertexNum;i++)
        for(j=0;j<vertexNum;j++)
    {
        arc[i][j]=0;
    }
 
    for(int p=0;p<arcNum;p++)
    {
        std::cout<<"输入第"<<p+1<<"条边及权值:"<<std::endl;
        std::cin>>i>>j>>k;
        arc[i][j]=k;
    }
 
}
 
void Floyd(MGraph G)
{
    int i,j,k;
    int dist[MaxSize][MaxSize]={0};
    for(i=0;i<G.vertexNum;i++)                 //初始化最短路径数组,使两点间路径初始为直接权值
        for(j=0;j<G.vertexNum;j++)
    {
        dist[i][j]=G.arc[i][j];
    }
    for(k=0;k<G.vertexNum;k++)
        for(j=0;j<G.vertexNum;j++)
            for(i=0;i<G.vertexNum;i++)
                if((dist[i][k]+dist[k][j]<dist[i][j]&&dist[i][k]!=0&&dist[k][j]!=0&&dist[i][j]!=0)||dist[i][j]==0)
    {
        dist[i][j]=dist[i][k]+dist[k][j];
    }
    for(i=0;i<G.vertexNum;i++)
        for(j=0;j<G.vertexNum;j++)
            if(i!=j)
        {
            std::cout<<G.vertex[i]<<"到"<<G.vertex[j]<<"的最短路径为:"<<dist[i][j]<<std::endl;
        }
}
int main()
{
 
    int e,n;
    std::cout<<"点的个数:"<<"  ";
    std::cin>>e;
 
    std::cout<<"边的个数:"<<"  ";
    std::cin>>n;
 
    char  s[e];
    for(int i=0;i<e;i++)
    {
        std::cout<<"输入第"<<i+1<<"个点:";
        std::cin>>s[i];
    }
    MGraph m(s,e,n);
    Floyd(m);
    return 0;
}

一起加油!学好数据结构和算法!!!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/148627.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 关于Raid0,Raid1,Raid5,Raid10的总结

    关于Raid0,Raid1,Raid5,Raid10的总结RAID0定义:RAID0又称为Stripe或Striping,它代表了所有RAID级别中最高的存储性能。RAID0提高存储性能的原理是把连续的数据分散到多个磁盘上存取,这样,系统有数据请求就

  • 最新Java学习教程路线图(2021完整版)

    最新Java学习教程路线图(2021完整版)各样的编程语言不断崛起,但唯有Java是牢牢占据着老大的位置,目前几乎90%以上的大中型互联网应用系统在服务器端开发首选Java。因此,也是吸引了不少年轻人投入到Java的学习之中。但不得不说,Java作为老牌编程语言,学习起来还是需要系统才行的。不少小伙伴会通过在网络上找各种各样的学习视频去研究学习,却往往缺乏了系统全面的学习路线。本文所有Java视频资料可点击免费领取所以,今天就跟大家分享一份系统的Java学习教程路线图,零基础也可以无压力的走进Java,学习Java!第一阶段、Java基础J

  • 快速排序—(面试碰到过好几次)

    快速排序—(面试碰到过好几次)原理:  快速排序,说白了就是给基准数据找其正确索引位置的过程.  如下图所示,假设最开始的基准数据为数组第一个元素23,则首先用一个临时变量去存储基准数据,即tmp=23;然后分别从数组的两端扫描数组,设两个指示标志:low指向起始位置,high指向末尾.  首先从后半部分开始,如果扫描到的值大于基准数据就让high减1,如果发现有元素比该基准数据的值小(如上图中18&lt…

  • 分秒必争域的时间同步问题[为企业部署Windows Server 2008系列十四]

    分秒必争域的时间同步问题[为企业部署Windows Server 2008系列十四]

  • HibernateTemplate详解

    HibernateTemplate详解HibernateTemplate提供非常多的常用方法来完成基本的操作,比如通常的增加、删除、修改、查询等操作,Spring2.0更增加对命名SQL查询的支持,也增加对分页的支持。大部分情况下,使用Hibernate的常规用法,就可完成大多数DAO对象的CRUD操作。下面是HibernateTemplate的常用方法简介:qvoiddelete(Objectentity):删除指定持久化实

  • HTTPS实现及安全方面

    HTTPS实现及安全方面

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号