最短路径问题

来源:互联网 发布:js怎么判断是不是数组 编辑:程序博客网 时间:2024/05/17 23:13

可以这样分:

(1)单源最短路径:从某固定源点出发,求其到所有其他顶点的最短路径

(2)多源最短路径:求任意两顶点间的最短路径

也可以这样分:

(1)无权图的最短路算法:直接BFS解决

(2)有权图的最短路算法:Dijkstra算法,Dijkstra算法是按照递增的顺序找出到各个顶点的最短路。

---------- 其实可以把权重展开分解为一个个权重为1的路径,这不就是无权图的最短路径嘛,

---------- 然后用BFS不就是按照步数一步步递增地找出节点并加入到结果集 嘛


---------- Dijkstra算法的优化:将dist存在最小堆中,节省每次找最小值的时间


到现在,单源的有权可以用Dijkstra算法,无权可以用BFS,那多源呢?

方法1:直接将单源最短路算法调用|V|遍(V为number of Vetext)

方法2:Floyd 算法




解释:类似与DP,将节点编号为0..n-1,dp[k][i][j]为从i节点到j节点,只结果0..k这些节点所能到的最短距离,那如果节点k+1的加入能使dp[i][j]变小,那就说明找到了一条更短的,如此n次以后,最后就把全部的顶点之间的最短路径都求出来了


Floyd题目可参考:https://pta.patest.cn/pta/test/3512/exam/4/question/83400

哈利·波特要考试了,他需要你的帮助。这门课学的是用魔咒将一种动物变成另一种动物的本事。例如将猫变成老鼠的魔咒是haha,将老鼠变成鱼的魔咒是hehe等等。反方向变化的魔咒就是简单地将原来的魔咒倒过来念,例如ahah可以将老鼠变成猫。另外,如果想把猫变成鱼,可以通过念一个直接魔咒lalala,也可以将猫变老鼠、老鼠变鱼的魔咒连起来念:hahahehe。

现在哈利·波特的手里有一本教材,里面列出了所有的变形魔咒和能变的动物。老师允许他自己带一只动物去考场,要考察他把这只动物变成任意一只指定动物的本事。于是他来问你:带什么动物去可以让最难变的那种动物(即该动物变为哈利·波特自己带去的动物所需要的魔咒最长)需要的魔咒最短?例如:如果只有猫、鼠、鱼,则显然哈利·波特应该带鼠去,因为鼠变成另外两种动物都只需要念4个字符;而如果带猫去,则至少需要念6个字符才能把猫变成鱼;同理,带鱼去也不是最好的选择。

输入格式:

输入说明:输入第1行给出两个正整数NNN (≤100\le 100100)和MMM,其中NNN是考试涉及的动物总数,MMM是用于直接变形的魔咒条数。为简单起见,我们将动物按1~NNN编号。随后MMM行,每行给出了3个正整数,分别是两种动物的编号、以及它们之间变形需要的魔咒的长度(≤100\le 100100),数字之间用空格分隔。

输出格式:

输出哈利·波特应该带去考场的动物的编号、以及最长的变形魔咒的长度,中间以空格分隔。如果只带1只动物是不可能完成所有变形要求的,则输出0。如果有若干只动物都可以备选,则输出编号最小的那只。

输入样例:

6 113 4 701 2 15 4 502 6 505 6 601 3 704 6 603 6 805 1 1002 4 605 2 80

输出样例:

4 70

package HarrPotter;import java.util.*;public class Main {    public static void main(String[] args) {        Scanner sc = new Scanner(System.in);        int n  = sc.nextInt(), m = sc.nextInt();        int[][] dist = new int[1+n][1+n];        for(int i=0; i<=n ;i++)        Arrays.fill(dist[i], 999999);        for(int i=0; i<=n; i++)        dist[i][i] = 0;                for(int p=0; p<m; p++) {        int i = sc.nextInt(), j = sc.nextInt(), d = sc.nextInt();        dist[i][j] = d;        dist[j][i] = d;        }                // Floyd        for(int k=1; k<=n; k++)        for(int i=1; i<=n; i++)        for(int j=1; j<=n; j++)        if(dist[i][k] + dist[k][j] < dist[i][j])        dist[i][j] = dist[i][k] + dist[k][j];                // find min(max)        int min = Integer.MAX_VALUE, idx = -1;        for(int i=1; i<=n; i++) {        int max = Integer.MIN_VALUE;        boolean f = false;        for(int j=1; j<=n; j++) {        if(dist[i][j] > max)  max = dist[i][j];        if(dist[i][j] == 999999) {        f = true;        break;        }        }        if(f)continue;                if(max < min) {        min = max;        idx = i;        }        }                if(min == Integer.MAX_VALUE)         System.out.println(0);        else        System.out.println(idx + " " + min);            }}


Dijkstra 题目可参考:https://pta.patest.cn/pta/test/3512/exam/4/question/83400

有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。

输入格式:

输入说明:输入数据的第1行给出4个正整数NNNMMMSSSDDD,其中NNN2≤N≤5002\le N\le 5002N500)是城市的个数,顺便假设城市的编号为0~(N−1N-1N1);MMM是高速公路的条数;SSS是出发地的城市编号;DDD是目的地的城市编号。随后的MMM行中,每行给出一条高速公路的信息,分别是:城市1、城市2、高速公路长度、收费额,中间用空格分开,数字均为整数且不超过500。输入保证解的存在。

输出格式:

在一行里输出路径的长度和收费总额,数字间以空格分隔,输出结尾不能有多余空格。

输入样例:

4 5 0 30 1 1 201 3 2 300 3 4 100 2 2 202 3 1 20

输出样例:

3 40

package TravelPlan;import java.util.*;/* * 注意两者不可达是距离是选择MaxValue还是999999,还是-1 * adj, dist都要初始化好 * 注意path和cost添加的位置 */public class Main {    public static void main(String[] args) {        Scanner sc = new Scanner(System.in);        int n = sc.nextInt(), m = sc.nextInt(), s = sc.nextInt(), t  =sc.nextInt();        int[][] adj = new int[n][n], fea = new int[n][n];        for(int[] i : adj)Arrays.fill(i, Integer.MAX_VALUE);                while(m-- > 0) {        int i = sc.nextInt(), j = sc.nextInt(), d = sc.nextInt(), f = sc.nextInt();        adj[i][j] = d;adj[j][i] = d;        fea[i][j] = f;fea[j][i] = f;        }                // Dijkstra        // initialization        boolean[] collected = new boolean[n];        int[] dist = new int[n], cost = new int[n];        Arrays.fill(dist, Integer.MAX_VALUE);        dist[s] = 0;                while(true) {                // find min        int minIdx = -1, minDis = Integer.MAX_VALUE;        for(int i=0; i<n; i++) {        if(!collected[i] && dist[i] < minDis) {        minDis = dist[i];        minIdx = i;        }        }                // check min exists        if(minIdx == -1)break;                // update        collected[minIdx] = true;        for(int to=0; to<n; to++)         if(adj[minIdx][to] != Integer.MAX_VALUE) {        if(dist[to] > dist[minIdx] + adj[minIdx][to]) {        dist[to] = Math.min(dist[to], dist[minIdx] + adj[minIdx][to]);        cost[to] = cost[minIdx] + fea[minIdx][to];        } else if(dist[to] == dist[minIdx] + adj[minIdx][to] && cost[to] > cost[minIdx] + fea[minIdx][to]) {        cost[to] = cost[minIdx] + fea[minIdx][to];        }        }        }                System.out.println(dist[t] + " " + cost[t]);            }}



0 0
原创粉丝点击