#hihocoder #1081 : 最短路径·一

hihocoder #1081 : 最短路径·一

标签(空格分隔): hihocoder

  笔试的时候遇到一道题,需要用到最短路径算法,之前虽然学过,但是一点不熟悉,搞了半天,最后还落得一个超时的下场。

  图文并茂的详细算法内容可见:Dijkstra算法

  这里的Dijkstra算法描述是基于邻接矩阵,对图的更省空间的描述是邻接表。稀疏图用矩阵很比较浪费空间。此处的图指无向图且权值为正的情况。权值为负时,如果有环则可能不存在最短路径。有环的情况下,最长路径不一定存在。负权存在寻找最短路径可以使用Bellman-Ford算法,和Dijkstra算法比较类似。
  Dijkstra算法主要使用两个长度等于图的顶点数数值的数组,一个数组dis[]用于记录起始点到某点的最短距离,一个数组vist[]用于记录是否已经找到起始点到该点的最短距离。当vist[i]==true时,dis[i]的值即为起始点到点i的最短路径长度;当vist[i]==false时,dis[i]的值为起始点到点i的可达值,可能还需要更新才能为最短路径值,如果为Inf之类的值,则表示不可达,即表示还没有边联通两点之间。
  每次从未访问的点中找出距离目标点最近的点,记录该点到起始点的最短距离并标记该点已访问。更新所有未访问节点到起始点的已知最短距离。
  Dijkstra算法可以从动态规划的角度去理解。动态规划:从新手到专家

题目:#1081 : 最短路径·一

Time Limit:10000ms
Case Time Limit:1000ms
Memory Limit:256MB
描述

万圣节的早上,小Hi和小Ho在经历了一个小时的争论后,终于决定了如何度过这样有意义的一天——他们决定去闯鬼屋!
在鬼屋门口排上了若干小时的队伍之后,刚刚进入鬼屋的小Hi和小Ho都颇饥饿,于是他们决定利用进门前领到的地图,找到一条通往终点的最短路径。
鬼屋中一共有N个地点,分别编号为1..N,这N个地点之间互相有一些道路连通,两个地点之间可能有多条道路连通,但是并不存在一条两端都是同一个地点的道路。那幺小Hi和小Ho至少要走多少路程才能够走出鬼屋去吃东西呢?

提示:顺序!顺序才是关键。

输入
每个测试点(输入文件)有且仅有一组测试数据。

在一组测试数据中:

第1行为4个整数N、M、S、T,分别表示鬼屋中地点的个数和道路的条数,入口(也是一个地点)的编号,出口(同样也是一个地点)的编号。
接下来的M行,每行描述一条道路:其中的第i行为三个整数u_i, v_i, length_i,表明在编号为u_i的地点和编号为v_i的地点之间有一条长度为length_i的道路。
对于100%的数据,满足N<=10^3,M<=10^4, 1 <= length_i <= 10^3, 1 <= S, T <= N, 且S不等于T。
对于100%的数据,满足小Hi和小Ho总是有办法从入口通过地图上标注出来的道路到达出口。

输出
对于每组测试数据,输出一个整数Ans,表示那幺小Hi和小Ho为了走出鬼屋至少要走的路程。

Sample Input

5 23 5 4
1 2 708
2 3 112
3 4 721
4 5 339
5 4 960
1 5 849
2 5 98
1 4 99
2 4 25
2 1 200
3 1 146
3 2 106
1 4 860
4 1 795
5 4 479
5 4 280
3 4 341
1 4 622
4 2 362
2 3 415
4 1 904
2 1 716
2 5 575

Sample Output

123

  这道题的两点之间可能存在多条路径,因此需要保存多条路径中最短的一条。此外,题目虽然说边的长度范围为1 <= length_i <= 10^3,但是一开始取Bignum=1005时,结果是WA,想了半天,郁闷了半天。最后抱着试一试的心态,把1005改为了10000,整个人心情才好点….

import java.util.Scanner;

public class Main {
    final static int Bignum = 10000;

    public static void main(String[] args) {
        Scanner sin = new Scanner(System.in);
        int N = sin.nextInt();
        int M = sin.nextInt();
        int st = sin.nextInt();
        int ed = sin.nextInt();
        sin.nextLine();
        int[][] graph = new int[N][N];
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                if (i == j) {
                    graph[i][j] = 0;
                } 
                else 
                    graph[i][j] = Bignum;
            }
        }

        while (M-- > 0) {
            int pot1 = sin.nextInt();
            int pot2 = sin.nextInt();
            int dist = sin.nextInt();
            sin.nextLine();
            if (dist < graph[pot1-1][pot2-1] && dist < graph[pot2-1][pot1-1]) {
                graph[pot1-1][pot2-1] = dist;
                graph[pot2-1][pot1-1] = dist;
            }
        }

        boolean[] vist = new boolean[N];
        for (int i = 0; i < N; i++) {
            vist[i] = false;
        }
        vist[st-1] = true;

        int[] dis = new int[N];
        for (int i = 0; i < N; i++) {
            dis[i] = graph[st-1][i];
        }
        dis[st-1] = 0;

        for (int i = 0; i < N; i++) {
            int min = Bignum;
            int mpot = st;
            for (int j = 0; j < N; j++) {
                if (!vist[j] && min > dis[j]) {
                    min = dis[j];
                    mpot = j;
                }
            }
            vist[mpot] = true;
            if (mpot == ed-1) {
                System.out.println(dis[mpot]);
                return;
            }
            for (int j = 0; j < N; j++) {
                if (!vist[j] && dis[j] > dis[mpot] + graph[mpot][j]) {  // 
                    dis[j] = dis[mpot] + graph[mpot][j];
                }
            }
        }
    }
}
点赞