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 575Sample 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];
}
}
}
}
}