欢迎光临
我们一直在努力

算法札记:Dijkstra算法正确性证明

Dijkstra算法正确性证明 精简考试答题版

1. 前置条件与定义
  • 适用场景:‌非负权边的单源最短路径图‌,源点为s
  • 集合定义:S为已确定最短路径的节点集合,U为未确定节点集合
  • 变量定义:dist[u]为源点经S内节点到u的当前最短距离,short[u]为源点到u的全局真实最短路径,满足short[u] ≤ dist[u]
2. 核心证明步骤(得分点)
  • ‌归纳基础‌:初始时S={s},dist[s] = short[s] = 0,命题成立。
  • ‌归纳假设‌:假设第k步时,S中所有节点均满足dist[u] = short[u],最短路径已正确确定。
  • ‌反证推导‌:第k+1步从U中选dist最小的节点v加入S,假设存在更短全局路径,该路径必然存在首个不在S内的节点y,由非负边权可得dist[y] < dist[v],与“v是U中dist最小节点”的算法规则矛盾,因此dist[v] = short[v]。
  • 3. 最终结论

    由数学归纳法,每一步加入S的节点都获得全局最短路径,算法终止时所有节点的最短路径均被正确求出,算法正确性得证。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<vector>
    #include<bitset>
    #define _for(i,a,b) for (int i=(a);i<(b);i++)
    using namespace std;
    typedef pair<int,int> PII;
    const int N=2e5+5,INF=0x3f3f3f3f;
    int n,m;
    int e[N],w[N],idx,h[N],ne[N];
    int d[N];
    bitset<N> vis;
    inline void init(){
    memset(h,-1,sizeof(h));
    idx=0;
    }
    inline void add(int a,int b,int c){
    e[idx]=b;
    w[idx]=c;
    ne[idx]=h[a];
    h[a]=idx++;
    }
    int dijsktra(){
    memset(d,0x3f,sizeof(d));
    priority_queue<PII,vector<PII>,greater<PII> > pq;
    pq.push({0,1});
    d[1]=0;
    while (!pq.empty()){
    PII now=pq.top();
    pq.pop();
    if (vis[now.second]){
    continue;
    }
    vis[now.second]=true;
    for (int i=h[now.second];~i;i=ne[i]){
    int j=e[i];
    if (d[j]>now.first+w[i]){
    d[j]=now.first+w[i];
    pq.push({d[j],j});
    }
    }
    }
    return d[n]==INF ? -1 : d[n];
    }
    int main(){
    init();
    scanf("%d%d",&n,&m);
    _for(i,0,m){
    int x,y,z;
    scanf("%d%d%d",&x,&y,&z);
    add(x,y,z);
    }
    printf("%d\\n",dijsktra());
    return 0;
    }

    赞(0)
    未经允许不得转载:171主机测评 » 算法札记:Dijkstra算法正确性证明
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址