最短路径 Dijkstra

一、算法流程

Dijkstra算法流程如下

  1. 初始化,集合K中加入结点1,结点1到结点1最短距离为0,到其它结点为无穷(或不确定)。
  2. 遍历与集合K中结点直接相邻的边(U,V,C),其中U属于集合K,V不属于集合K,计算由结点1出发按照已经得到的最短路到达U,再由U经过该边到达V时的路径长度。比较所有与集合K中结点直接相邻的非集合K结点该路径长度,其中路径长度最小的结点被确定为下一个最短路径确定的结点,其最短路径长度即为这个路径长度,最后将该结点加入集合K。
  3. 若集合K中已经包含了所有的点,算法结東;否则重复步骤2。

二、实例:

1. 牛客网 最短路径

因为需要考虑s是否可以到达t,因此先用djs算出最短路径,同时存储前驱结点,最后用DFS深度遍历路径看起点终点是否相连

#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
#define N 10001
#define INF 100000
struct edge{
    int next;  //下一跳
    int W;      //权重
};

int n,m,S,T;  //n,m,起点S和终点T
int dis[N];   //最小距离
bool vis[N];   //是否访问过
bool flag=false;  //起点能够到达终点

void dfs(int d,vector<int> pre[N]){
    if(d==S){
        flag=true;
        return;
    }
    else{
        //权重相同时有多个前驱节点
        for(int i=0;i<pre[d].size();i++){
             dfs(pre[d][i],pre);
        }
    }
}


void dijsktra(vector<int> pre[N],vector<edge> edges[N]){
    //初始化
    int nextG=S;
    dis[S]=0;
    vis[S]=true;
    for(int i=0;i<n;i++){
        for(int j=0;j<edges[nextG].size();j++){
            int t=edges[nextG][j].next; //下一跳
            int w=edges[nextG][j].W; //长度
            if(vis[t]==true) continue;
            //更新信息
            if(dis[t]==-1||dis[t]>dis[nextG]+w){
                dis[t]=dis[nextG]+w;
                pre[t].clear();
                pre[t].push_back(nextG);
            }
            //权重相同时有多个前驱节点
            else if(dis[t]==-1||dis[t]==dis[nextG]+w){
                dis[t]=dis[nextG]+w;
                pre[t].push_back(nextG);
            }
        }
        int minDis=INF;
        //选取最小的作为下一跳
        for(int j=1;j<n;j++){
            if(dis[j]!=-1&&dis[j]<minDis&&vis[j]==false){
                minDis=dis[j];
                nextG=j;
            }
        }
        vis[nextG]=true;  //标记已访问
    }
}


int main(){
    vector<edge> egdes[N];  //邻接边
    vector<int> pre[N];   //前驱节点
    fill(dis,dis+N,-1);
    scanf("%d %d %d %d",&n,&m,&S,&T);
    while(m--){
        int a,b,w;
        scanf("%d%d%d",&a,&b,&w);   //节点a,b和权重c
        edge tmp;
        tmp.next=b;
        tmp.W=w;
        egdes[a].push_back(tmp);  //单向,只加入一边
    }
    dijsktra(pre,egdes);
    dfs(T,pre);    //检验起点终点是否相通
    if(flag)
        printf("%d",dis[T]);
    else
       printf("%d",-1);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值