今天看到一篇文章http://www.kidscode.cn/archives/3406
关于Dijkstra事迹的,就··研究一下最短路径算法,用java实现一下下,
基本照着 http://blog.51cto.com/ahalei/1387799 抄的··理解的也是囫囵吞枣。一会儿再去雕琢一下。先把代码放这儿
下面代码可以直接粘贴到IDE中执行,图矩阵已经写入代码
import java.util.ArrayList;
import java.util.Arrays;
public class DijkstraTest {
public static void main(String[] args) {
// 初始化数据
/** * 邻接矩阵 * 第一行两个整数 n m。 * n 表示顶点个数(顶点编号为 1~n),m 表示边的条数。 * 接下来 m 行表示,每行有 3 个数 x y z。表示顶点 x 到顶点 y 边的权值为 z。 * 6 9 1 2 1 1 3 12 2 3 9 2 4 3 3 5 5 4 3 4 4 5 13 4 6 15 5 6 4 */
String data = "6 9 1 2 1 1 3 12 2 3 9 2 4 3 3 5 5 4 3 4 4 5 13 4 6 15 5 6 4";
ArrayList<Integer> datas = new ArrayList<Integer>();
for(String s:data.split(" ")){
datas.add(Integer.valueOf(s));
}
//读入n和m,n表示顶点个数,m表示边的条数
int n = datas.get(0);
int m = datas.get(1);
int inf = 999999;
int min = 999999;
int[][] e = new int[n][n];
// 先把矩阵的元素都设为 inf
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(i==j){
e[i][j] = 0;
}else {
e[i][j] = inf;
}
}
}
for(int i=2;i<datas.size();i += 3){
e[datas.get(i)-1][datas.get(i+1)-1] = datas.get(i+2);
}
// 打印出矩阵
System.out.println("------------------邻接矩阵--------------------------");
for(int i=0;i<n;i++){
System.out.println(i+1+" "+Arrays.toString(e[i]));
}
//初始化dis数组,这里是1号顶点到其余各个顶点的初始路程
int[] dis = e[0];
System.out.println("------------------初始dis数组--------------------------");
System.out.println(Arrays.toString(dis));
// book 数组初始化 1表示确定值,0表示估计值
int[] book = new int[n];
for(int i=0;i<n;i++){
book[i] = 0;
}
book[0] = 1;
//Dijkstra算法核心语句
int u=0;
for(int i=0;i<n-1;i++){
min = inf;
//找到估计值(book[j]==0)中 离1号顶点最近的顶点
for(int j=0;j<n;j++){
if(book[j]==0 && dis[j]<min){
min = dis[j];
u = j;
}
}
// u 是最近点,下面以u为扩散点遍历
book[u] = 1;
for(int v=0;v<n;v++){
if(dis[v] > dis[u]+e[u][v]){
dis[v] = dis[u]+e[u][v];
}
}
}
System.out.println("----------------------结果-------------------------------");
System.out.println(Arrays.toString(dis));
}
}
执行结果
------------------邻接矩阵--------------------------
1 [0, 1, 12, 999999, 999999, 999999]
2 [999999, 0, 9, 3, 999999, 999999]
3 [999999, 999999, 0, 999999, 5, 999999]
4 [999999, 999999, 4, 0, 13, 15]
5 [999999, 999999, 999999, 999999, 0, 4]
6 [999999, 999999, 999999, 999999, 999999, 0]
------------------初始dis数组--------------------------
[0, 1, 12, 999999, 999999, 999999]
----------------------结果-------------------------------
[0, 1, 8, 4, 13, 17]
本来以为想通了,但是仔细想想还是不通。
此代码得到结果了,我想本来想改改把图的过程打印出来的,没成功,还改着改着就··怀疑原来的想法了。
- 为什么每次只需遍历估计值中最小的,就是最小路径?
8点了,从5点半坐在电脑前,没吃饭到现在。脑子不清晰了。下回分解吧··
8点半了··实在不甘心,似乎想通了上面的问题,但是不晓得怎么用语言描述。
而且··根据这个代码,打印出路径会很麻烦··懒得想了··回去洗澡··再说·
第二天早上还是放不下,又找了找,
发现一个可以打印出路径的例子 https://blog.csdn.net/qq_35644234/article/details/60870719,为啥我就想不出来呢···
这篇文章代码很工整,堪称模板,其实··我也想把dis改成类··但是时间紧迫,优化··再说吧,上代码
import java.util.ArrayList;
import java.util.Arrays;
public class DijkstraTest {
public static void main(String[] args) {
// 初始化数据
/** * 邻接矩阵 * 第一行两个整数 n m。 * n 表示顶点个数(顶点编号为 1~n),m 表示边的条数。 * 接下来 m 行表示,每行有 3 个数 x y z。表示顶点 x 到顶点 y 边的权值为 z。 * 6 9 1 2 1 1 3 12 2 3 9 2 4 3 3 5 5 4 3 4 4 5 13 4 6 15 5 6 4 */
// String data = "6 9 1 2 1 1 3 12 2 3 9 2 4 3 3 5 5 4 3 4 4 5 13 4 6 15 5 6 4";
String data = "6 8 1 3 10 1 5 30 1 6 100 2 3 5 3 4 50 4 6 10 5 6 60 5 4 20";
ArrayList<Integer> datas = new ArrayList<Integer>();
for(String s:data.split(" ")){
datas.add(Integer.valueOf(s));
}
//读入n和m,n表示顶点个数,m表示边的条数
int n = datas.get(0);
int m = datas.get(1);
int inf = 999999;
int min = 999999;
int[][] e = new int[n][n];
// 先把矩阵的元素都设为 inf
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(i==j){
e[i][j] = 0;
}else {
e[i][j] = inf;
}
}
}
for(int i=2;i<datas.size();i += 3){
e[datas.get(i)-1][datas.get(i+1)-1] = datas.get(i+2);
}
// 打印出矩阵
System.out.println("------------------邻接矩阵--------------------------");
for(int i=0;i<n;i++){
System.out.println(i+1+" "+Arrays.toString(e[i]));
}
// 以begin为起点
int begin = 0;
//初始化dis数组,这里是begin顶点到其余各个顶点的初始路程
int[] dis = e[begin];
System.out.println("------------------初始dis数组--------------------------");
System.out.println(Arrays.toString(dis));
// book 数组初始化 1表示确定值,0表示估计值
int[] book = new int[n];
// 记录最短路径
String[] path = new String[n];
for(int i=0;i<n;i++){
book[i] = 0;
path[i] = (begin+1)+" --> "+(i+1);
}
book[begin] = 1;
//Dijkstra算法核心语句
int u=0;
for(int i=0;i<n-1;i++){
min = inf;
//找到估计值(book[j]==0)中 离1号顶点最近的顶点
for(int j=0;j<n;j++){
if(book[j]==0 && dis[j]<min){
min = dis[j];
u = j;
}
}
// u 是最近点,下面以u为扩散点遍历
book[u] = 1;
for(int v=0;v<n;v++){
//如果新得到的边可以影响其他为访问的顶点,那就就更新它的最短路径和长度
if(e[u][v]<inf && dis[v] > dis[u]+e[u][v]){
dis[v] = dis[u]+e[u][v];
path[v] = path[u] + " --> "+(v+1);
}
}
}
System.out.println("---------------以"+(begin+1)+"为起点的图的最短路径为-------------------");
System.out.println(Arrays.toString(dis));
System.out.println("");
for(int i=0;i<n;i++){
System.out.println(path[i]+" = "+dis[i]);
}
}
}
运行结果
------------------邻接矩阵--------------------------
1 [0, 999999, 10, 999999, 30, 100]
2 [999999, 0, 5, 999999, 999999, 999999]
3 [999999, 999999, 0, 50, 999999, 999999]
4 [999999, 999999, 999999, 0, 999999, 10]
5 [999999, 999999, 999999, 20, 0, 60]
6 [999999, 999999, 999999, 999999, 999999, 0]
------------------初始dis数组--------------------------
[0, 999999, 10, 999999, 30, 100]
---------------以1为起点的图的最短路径为-------------------
[0, 999999, 10, 50, 30, 60]
1 --> 1 = 0
1 --> 2 = 999999
1 --> 3 = 10
1 --> 5 --> 4 = 50
1 --> 5 = 30
1 --> 5 --> 4 --> 6 = 60
调整了两个地方:
- 可以打印最短路径
- 可以自定义begin,以begin为起点查询最短路径
那么··又有问题了
- 负权重的边怎么解决?
- 此代码是有向图,无向图怎么办? 无向图的话那么邻接矩阵就是对称的,data反过来复制一份,有没有更好的解决办法?
下回分解哈