dij算法理解

生来就可爱ヽ(ⅴ<●) 提交于 2020-02-22 15:55:08

(不能有负权边)
!长度步数显示法!
集合1:已最短点集合
集合2:未最短点到源点距离集合
第一开始把和源点连接的点的距离排序起来
那么2里最小的一定是源点到这个点的最短路径
因为从源点如果想到这个点有一条其它更短路径
那么这个路径只能是1集合到这个点,如果从2集合就已经更长了
而集合1里到这个点的路径已经被松弛过了是最短的

接下来再往下松弛(用当前节点更新别的节点的距离)
那么2里最小的,一定是源点到这个点的最短路径
因为从源点出发,如果不是经历的当前同样路径,想更短
那么这个路径只能是1集合到这个点,如果2集合就已经更长了
而集合1里到这个点的路径已经被松弛过了是最短的

1:dij本质上其实是贪心
2:不可能用比当前最短的路径长的路径去更新别的路径
3:每次都会找到一个最短的路径

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
int main()
{
    int N,M,A,B,C,temp;
    int dis[105],mp[105][105];
    bool vis[105];
    while((N=read())&&(M=read()))
    {
        for(int i=1;i<=N;i++)
            for(int j=1;j<=N;j++)
                mp[i][j]=10000000;
        for(int i=1;i<=N;i++) dis[i]=10000000;
        for(int i=1;i<=N;i++) vis[i]=0;
        dis[0]=10000000; //!!!!!!!!!!!
        dis[1]=0;
        for(int i=1;i<=M;i++)
        {
            A=read(); B=read(); C=read();
            if(mp[A][B]>C) mp[A][B]=C;
            if(mp[B][A]>C) mp[B][A]=C;
        }
        for(int i=1;i<=N;i++)
        {
            temp=0;
            for(int i=1;i<=N;i++)
            {
                if(!vis[i]&&dis[i]<dis[temp]) temp=i;
            }
            vis[temp]=1;
            if(temp==N) break;
            for(int i=1;i<=N;i++)
            {
                if(dis[temp]+mp[temp][i]<dis[i]) dis[i]=dis[temp]+mp[temp][i];
            }
        }
        printf("%d\n",dis[N]);
    }
    return 0;
}

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!