ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

单源最短路问题复习

2021-10-23 22:33:10  阅读:224  来源: 互联网

标签:复习 int 短路 单源 数组 500001 include 起点 dis


在学习单源最短路之前,首先要了解数组和for循环

  • for循环

for循环,顾名思义就是循环语句

运行以下代码

#include<iostream>
#include<cstring>
using namespace std;
int main(){
    for(int i=0;i<=10;i++){
        cout<<i<<' ';
    }
    return 0;
}

得到

 

 

 运行以下代码

#include<iostream>
#include<cstring>
using namespace std;
int main(){
    for(int i=0;i<=10;i++){
        cout<<i<<endl;
        for(int j=0;j<=10;j++){    
          cout<<j<<' ';
        }
        cout<<endl;
    }
    return 0;
}

得到

 

 

 这两个例子可以直观地理解for循环的运行方式和效果

  • 数组

对于一维数组,形式上可以理解为一个数值可变的数列

对于二维数组,形式上可以理解为一个矩阵

其作用是有序地储存变量,

例子如下

#include<iostream>
#include<cstring>
using namespace std;
int main(){
    int a[10][10];//声明一个10*10的二维数组,仅做储存数据使用,无数学意义 
    memset(a,127,sizeof(a));//将数组中的所有元素全赋值为2139062143
    for(int i=0;i<10;i++){
        for(int j=0;j<10;j++){
            cout<<a[i][j]<<' ';
        }
        cout<<endl;
    }//for循环输出 
    return 0; 
}

运行后输出结果

 需要注意的是,数组的下标从0开始计算;

如:a[10]中包含的元素为a[0]~a[9]

但是在处理问题的时候通常忽略掉a[0],从a[1]开始初始化

  • 单源最短路问题介绍

 

对于如图所示的图,字母表示节点,也即地点,其中相连的边表示两点间的距离

单源最短路问题是指以一个节点为起点,求它到其余每个点的最短距离

  • 图的存储方式

在输入时,第一行为n,m,s三个数字,分别表示该图的点数和边数,以及起点;目标是求该起点到其余各点的最短路径

之后m行,每行的第一个数字为该边的起点编号,第二个数字为终点编号,第三个数字为该边的长度

eg:

 

 

 

 

 

 

我们以数组dis[]表示起点s到每个点的路径长度

初始化时令dis[s]=0

dis[i]=2147483647,其中i<=n且i!=s

(dis[s]即s到自身的距离,为0;而开始时,s到其余各点的距离未知,设为不可到达,用一个很大的数表示即可)

以数组u[],v[],w[],分别表示边i的起点,终点,长度(w表示weight,权重)

则可有以下的输入代码

        int n,m,s,u[500001],v[500001],w[500001]
        cin>>n>>m>>s;
    for(int i=1;i<=m;i++){
        cin>>u[i]>>v[i]>>w[i];
        }
    for(int i=1;i<=n;i++)
        dis[i]=2147483647;
        dis[s]=0;

至此,整个图储存完毕

  • 求起点s到所有点的最短路径

比较好理解的:若存在边(u[j],v[j],w[j])使得dis[v[j]]>dis[u[j]]+w[j]

则说明起点s先到u[j]再到v[j]比s直接到v[j]更快

则令dis[v[j]]=dis[u[j]]+w[j],保证最小

要进行上述操作,则只需运行如下代码

for(int j=1;j<=m;j++){
       if(dis[v[j]]>dis[u[j]]+w[j]){
               dis[v[j]]=dis[u[j]]+w[j];
           }
       }

如果只进行一次上述操作,那么dis[]中存储的结果只会是和s相邻的边(可以在纸上手动运行以下代码),其余边没有进行迭代

为了让除s外的n-1个点都被遍历到,我们需要进行n-1次上述操作,即

for(int i=1;i<=n-1;i++){//该外层i循环在这里只是个计数作用 
	        for(int j=1;j<=m;j++){
	            if(dis[v[j]]>dis[u[j]]+w[j]){
	                dis[v[j]]=dis[u[j]]+w[j];
	            }
	        }
	}

至此,dis[i]中的数均变为s到i点的最短路径

最后输出即可

    for(int i=1;i<=n;i++)
        cout<<dis[i]<<" ";
    return 0;

 

优化先不谈

总体代码如下:

#include<bits/stdc++.h>
using namespace std;
int u[500001],v[500001],w[500001];
long long dis[500001];
int n,m,s;
int main(){
    cin>>n>>m>>s;
    for(int i=1;i<=n;i++)
        dis[i]=2147483647;
        dis[s]=0;
    for(int i=1;i<=m;i++){
        cin>>u[i]>>v[i]>>w[i];
    }
    for(int i=1;i<=n-1;i++){
            for(int j=1;j<=m;j++){
                if(dis[v[j]]>dis[u[j]]+w[j]){
                    dis[v[j]]=dis[u[j]]+w[j];
                }
            }
    }
    for(int i=1;i<=n;i++)
        cout<<dis[i]<<" ";
    return 0;
}

将上述例子中的数代入计算一下(用手)

得到可以输出dis数组是

0 2 4 3

算法时间复杂度为O(n*m),非常慢,当n*m比较大时计算机无法承受

 

end

标签:复习,int,短路,单源,数组,500001,include,起点,dis
来源: https://www.cnblogs.com/djhsbdb/p/15449686.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有