HDU 2544 最短路 //Dijkstra 算法 边权必须非负

本文详细介绍迪杰斯特拉算法的原理与应用,该算法适用于无负权回路且边权非负的情况,用于求解单源最短路径问题。通过实例讲解如何逐步更新最短路径,提供了一个具体的实现代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最短路

 

Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 81686    Accepted Submission(s): 35376

 

 

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 11 2 33 31 2 52 3 53 1 20 0

 

Sample Output

 

32

 

 

Source

UESTC 6th Programming Contest Online

 

 

Recommend

lcy   |   We have carefully selected several similar problems for you:  2066 1874 1217 2112 1142 

 

 

Statistic | Submit | Discuss | Note

 

 

参考网址:::https://blog.youkuaiyun.com/u012469987/article/details/51319574

Dijkstra

通俗翻译为迪杰斯特拉算法
- 适用范围:无负权回路,边权必须非负,单源最短路
- 时间复杂度:优化前O(n2

)

简单粗暴的原理

更新:2018-02-21
求t 点到s点的距离,假设距离s点最近的点p1距离为L,那么这个点一定是最短的,因为不可能有比直达最近的点还近的路,那么选它没错。

然后把s和点p1看成一个点S’,再同理选距离S’最近的点(其实这里实际求的是距离最开始的源点s),就这样一直重复操作贪心下去即可。

其中在选了p1之后我们要更新所有p1点相邻点到s点的最短距离,因为选p1点那么可能经过p1点到s点比原本的点直接到s点更近。

注意求点距离的时候求的是距离源点s最近,不是距离集合S’最近,距离集合S’最近就是最小生成树Prim算法了。

过程

数组dis[u]表示u到s点的最短距离。
我们一直找点u = min{ dis[k] , k点未访问 },这个点就是最短路上的点,然后根据其他点v跟u点的关系去更新下dis[v],不断重复找和更新即可。
dis[s]=0将源点加入最短路,然后循环n-1次每次找出一个最短路上的点,找的方法是直接找出剩下的点中dis[ ]最小的那个点u,u点就是最短路上的点,然后看看其他点v到s点的距离会不会因为这个u点的加入而改变,即若dis[v] > dis[u] + distance[u][v] 则更新dis[v]为 dis[u] + distance[u][v]。

 

在最开始时,只有起点s的最短距离是确定的,而在尚未标记过的定点中,距离dis[i]最小的顶点就时最短距离已经确定的顶点,由于不存在负边,所以dis[i]不会在之后的更新中变小

 

 

          for(int k=1;k<=n;k++)  //不断更新相邻的点
        {
            if(vis[k]==0 && dis[k]>dis[u]+mp[u][k])
                dis[k]=dis[u]+mp[u][k];    
        }

 

根据题意,先从1出发集合T{1},找距离1点最近的点,这个点是4,将4加入集合T{1,4},再找其他的2 3 5 未被标记的点,例如(从4点到2点的距离大于从1直接到2的距离,所以dis[2]中的距离不用更新;从4点到3点的距离小于从1点直接到3点的距离那么就更新dis[3]中的距离,把距离换成1-4-3的距离,即2+9=11;从4点到5点的距离为(1-4-5 2+3=5)小于从1直接到5的距离,所以更新dis[5]中的距离为(2+3=5),这样就将其他的临界点都更新了一遍,然后再执行一次循环,找其他的除了1和4的其他的点,所有的点都找一遍,都更新一遍之后,dis中存放的就是最小的距离,我们要找的是从1到n的距离,所以直接输出dis[n]就可以了)

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<string.h>
using namespace std;
#define INF 0x3f3f3f3f
#define maxn 10001
int dis[maxn];
int mp[105][105];
int vis[maxn];
int n,m;
int Dijkstra(int s, int t)
{
    for(int i=1;i<=n;i++)
    {
        dis[i]=mp[s][i];  //dis[i]中存放的是从起始点s到其他各点的距离
    }
    dis[s]=0; //将起始点的距离标记为0
    vis[s]=1; //将起始点标记
    for(int i=1;i<n;i++)  //寻找除了s点外的其他n-1个点
    {
        int u,t=INF;
        for(int j=1;j<=n;j++)  //找最小的dis[]
        {
            if(vis[j]==0 && t>dis[j] )
            {
                u=j;   
                t=dis[j];
            }
        }
        vis[u]=1; //标记找到的最短距离的点
        for(int k=1;k<=n;k++)  //不断更新相邻的点
        {
            if(vis[k]==0 && dis[k]>dis[u]+mp[u][k])
                dis[k]=dis[u]+mp[u][k];    
        }
    }
    return dis[t];
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int a,b,c;
        memset(mp,INF,sizeof(mp));
        memset(vis,0,sizeof(vis));
        if(n==0 || m==0)
            break;
        for(int i=1;i<=n;i++)
        {
            mp[i][i]=0;
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            mp[a][b]=c;
            mp[b][a]=c;
        }
        int res=Dijkstra(1,n);
        cout<<res<<endl;
    }
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值