在网上查了一下,加权无向图最短路解法DFS和Dijkstra多一些,一般不用BFS
我选择用DFS,用时380MS,看了一下其他人的,最好的是240MS,用的是Dijkstra。都是采用邻接矩阵存储图结构。
在DFS的过程中,开始我的做法是,每找到一条从s到t的路径就存储起来,最后将最优路径输出。后来优化一下,在找路径的过程中,即DFS方法内部就可以判断出来(通过设置全局变量),这样最后DFS方法返回后,直接输出最短路径就可以。
DFS和Dijkstra的时间区别就在于核心方法DFS和Dijkstra上,所以还是Dijkstra优一些。这些算法要以后慢慢练习啦,比如之前的快排,今天遇到的Dijkstra,练习一次就好了。
代码:
package Test1;
import java.util.Scanner;
public class Test53 {
/**
* by qr jobdu 1008 2014-8-7(8) graph:shortest path
*/
static int mind=Integer.MAX_VALUE;
static int minp=Integer.MAX_VALUE;
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n, m;
n = scan.nextInt(); // number of node
m = scan.nextInt(); // number of edge
while (!(n == 0 && m == 0)) {
int edgeD[][] = new int[n + 1][n + 1]; // node number is 1-->n
int edgeP[][] = new int[n + 1][n + 1];
boolean flag[] = new boolean[n + 1]; // flag node pass situation(不要忘记加一个标记数组记录节点是否被访问过,迷宫也一样)
for (int i = 1; i < n + 1; i++) {
flag[i] = false;
for (int j = 1; j < n + 1; j++)
edgeD[i][j] = 0; // 0 represent no edge
}
for (int i = 0; i < m; i++) {
int a = scan.nextInt();
int b = scan.nextInt();
edgeD[a][b] = scan.nextInt();
edgeD[b][a] = edgeD[a][b];
edgeP[a][b] = scan.nextInt();
edgeP[b][a] = edgeP[a][b];
}
int s = scan.nextInt();
int t = scan.nextInt();
// dfs get the shortest path
flag[s] = true;
DFS(s, t, edgeD, edgeP, n, 0, 0, flag);
//output result
System.out.println(mind+" "+minp);
mind=Integer.MAX_VALUE; //!important
minp=Integer.MAX_VALUE;
n = scan.nextInt();
m = scan.nextInt();
}
}
private static void DFS(int a, int b, int[][] edgeD, int[][] edgeP, int n,
int d, int p, boolean flag[]) {
if (a == b) {
//在过程中就可以判断出来最小的,而无需返回再判断
if(mind>d || (mind==d && minp>p)){
mind=d;
minp=p;
}
} else {
for (int i = 1; i < n + 1; i++) {
if (edgeD[a][i] != 0 && !flag[i]) { //flag[i]=false
flag[i] = true;
DFS(i, b, edgeD, edgeP, n, d + edgeD[a][i],
p + edgeP[a][i], flag);
flag[i]=false; //访问之后记得将状态变回来,无需创建一个一样大小的数组
}
}
}
}
}
通过这道题,我也得到了一些经验:
1.当每次while结束时,要将全局变量重新赋值
2.需要一个非常大的数的时候,使用Integer.MAX_VALUE
3.DFS找最短路径,要设置一个flag变量。递归找路径一般都需要设这样一个标记结点是否被访问的数组,如DFS,迷宫。而当访问过后,因为还需要找其他路径,所以不要忘记将flag变回false
我觉得这样练习OJ真的可以提高自己的编程能力,获得编程经验,继续加油!