贪心算法-4 Shortest path

本文介绍了Dijkstra算法解决有向带权图中最短路径问题的原理和过程,包括算法简介、证明步骤以及一个具体的例题解析,展示了如何在实际问题中应用Dijkstra算法找到两点间的最短路径。
摘要由CSDN通过智能技术生成

Shortest path

1 简介

给定有向带权图G=(V,E),E中的每条边权值为非负实数。给定一点s,求s到其它点的最短路径。

对于这类问题,我们常用Dijkstra算法。

所谓Dijkstra算法,即开始时,集合S为空,集合Q为所有点以及它们到s的距离。之后,如果Q不为空,那选取Q中与s距离最短的点u,将该点加入S,之后更新u的所有临近点v,如果 d s v > d s u + d u v d_{sv}>d_{su}+d_{uv} dsv>dsu+duv,那么 d s v = d s u + d u v d_{sv}=d_{su}+d_{uv} dsv=dsu+duv

伪代码如下:

S={}
Q=G.V
while Q!={}:
	u=Extract_min(Q)
	S=SU{u}
	for each vertex v connect with u:
		Update(v)

2 证明

在 算 法 执 行 过 程 中 , ∀ u ∈ S , 路 径 P s u 是 最 短 的 。 在算法执行过程中,\forall u\in S, 路径P_{su}是最短的。 uSPsu

证明(用演绎法):

|S|=1,S={s},Pathss=0。

假设|S|=k(k ≥ 1)时该说法仍然成立。

现在将v加入S,使得|S|=k+1。令(u,v)为路径 P s v P_{sv} Psv上的最后一条边。

根据假设, P s u P_{su} Psu是s到u的最短路径。假设存在另外一条s-v的路径P,我们需要证明 P ≥ P s v P ≥ P_{sv} PPsv 。为了到达v,该路径必然在某处离开集合S,设y为该路径离开S后经过的第一个节点,x为y之前的点。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kjX7SC8s-1594293018073)(D:\CS-Recorder\CS-2-2\ADA\dijkstra-proof.png)]

根据算法,每次会选择S之外离s最近的点,因此有如下不等式成立:

l ( P s x + ( x , y ) ) ≥ l ( P s u + ( u , v ) ) , 所 以 l ( P ) = l ( P s x + ( x , y ) + P y v ) ≥ l ( P s u + ( u , v ) ) = l ( P s v ) l(P_{sx}+(x,y))\ge l(P_{su}+(u,v)),所以l(P)=l(P_{sx}+(x,y)+P_{yv})\ge l(P_{su}+(u,v))=l(P_{sv}) l(Psx+(x,y))l(Psu+(u,v))l(P)=l(Psx+(x,y)+Pyv)l(Psu+(u,v))=l(Psv)

所以s到S中任意一点的路径距离都是最短的。

3 例题

问题描述

给定一张图,求第一个点和第N个点之间的最短路径。在这里,路径定义为该路径上所有边的乘积。

输入

第一行有两个数字NM

接下的M行,每行包含三个数字u,v,w,表示一条从uv的有向路径,权值为w

输出

输出最短路径的值,结果需要模19260817。

输入样例

3 2
1 2 3
2 3 4

输出样例

12

参考代码

import java.util.ArrayList;
import java.util.Scanner;

public class Main1 {
    static class node {
        ArrayList<Integer> childIndex = new ArrayList<>();
        ArrayList<Integer> path = new ArrayList<>();

        node() {
        }
    }

    static class element {
        int index;
        double dist;
        int preIndex;

        element(int index, double dist, int preIndex) {
            this.index = index;
            this.dist = dist;
            this.preIndex = preIndex;
        }
    }

    public static void exchange(element[] pq, int i, int j) {
        element temp = pq[i];
        pq[i] = pq[j];
        pq[j] = temp;
    }

    public static void raise(element[] pq, int tail) {
        int k = tail;
        while (k > 1 && pq[k / 2].dist > pq[k].dist) {
            exchange(pq, k / 2, k);
            k = k / 2;
        }
    }

    public static void sink(element[] pq, int tail) {
        int k = 1;
        while (2 * k <= tail) {
            int j = 2 * k;
            if (j + 1 <= tail && pq[j + 1].dist < pq[j].dist) {
                j++;
            }
            if (pq[k].dist > pq[j].dist) {
                exchange(pq, k, j);
                k = j;
            } else {
                break;
            }
        }
    }

    static int Mod = 19260817;

    public static void main(String[] args){
        Scanner in = new Scanner();

        int n = in.nextInt();
        int m = in.nextInt();

        boolean[] isIn = new boolean[n + 1];
        node[] nodeList = new node[n + 1];
        int[] preNode = new int[n + 1];

        for (int i = 1; i <= n; i++) {
            nodeList[i] = new node();
        }

        for (int i = 0; i < m; i++) {
            int index = in.nextInt();
            nodeList[index].childIndex.add(in.nextInt());
            nodeList[index].path.add(in.nextInt());
        }

        element[] pq = new element[n * 500];
        pq[1] = new element(1, 0, -1);
        int tail = 1;

        while (!isIn[n]) {
            while (isIn[pq[1].index]) {
                exchange(pq, 1, tail);
                tail--;
                sink(pq, tail);
            }

            element outElement = pq[1];
            node outNode = nodeList[pq[1].index];

            preNode[outElement.index] = outElement.preIndex;
            isIn[pq[1].index] = true;

            if (isIn[n]) {
                break;
            }

            exchange(pq, 1, tail);
            tail--;
            sink(pq, tail);

            for (int i = 0; i < outNode.childIndex.size(); i++) {
                if (!isIn[outNode.childIndex.get(i)]) {
                    tail++;
                    pq[tail] = new element(outNode.childIndex.get(i), Math.log(outNode.path.get(i)) + outElement.dist, outElement.index);
                    raise(pq, tail);
                }
            }
        }

        int now_index = n;
        long result = 1;
        while (now_index != 1) {
            int pre_index = preNode[now_index];

            node chooseNode = nodeList[pre_index];

            int minPath = 1000000;

            for (int i = 0; i < chooseNode.childIndex.size(); i++) {
                if (chooseNode.childIndex.get(i) == now_index && chooseNode.path.get(i)<minPath) {
                    minPath = chooseNode.path.get(i);
                }
            }

            result = (result * minPath%Mod) % Mod;

            now_index = pre_index;
        }

        System.out.println(result);
    }
}

eNode.path.get(i);
}
}

        result = (result * minPath%Mod) % Mod;

        now_index = pre_index;
    }

    System.out.println(result);
}

}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值