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

最短路

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
 

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

Statistic | Submit | Discuss | Note


参考网址:::https://blog.csdn.net/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;
    }
}



猜你喜欢

转载自blog.csdn.net/lmengi000/article/details/80154140