贪心算法解决dijkstra最短路径问题
1.计算过程
如图:
初始:定义两个数组:dist[],visit[]
;一个用来计算距离,一个用来记忆化搜索(搜过的不会再去搜索)。
现在从
V
0
V_0
V0结点出发。初始化 dist[0,inf,inf,inf,inf,inf]
(在这里设置0与0结点的距离为0)与 visit[1,0,0,0,0,0]
(在这里标记0结点已经搜过) 。执行步骤如下:
-
第一步:
找到 V 0 V_0 V0相连的边 V 2 , V 4 , V 5 {V_2,V_4,V_5} V2,V4,V5,计算距离:
dist[0,inf,10,inf,30,100]
( 如 果 d i s t [ V 0 ] + 权 值 ( V 0 − V i 的 权 值 ) < d i s t [ V i ] ( i = 2 , 4 , 5 ) , 那 么 就 更 新 d i s t [ V i ] 的 距 离 为 d i s t [ V 0 ] + 权 值 如果dist[V_0]+权值(V_0-V_i的权值)<dist[V_i](i=2,4,5),那么就更新dist[V_i]的距离为dist[V_0]+权值 如果dist[V0]+权值(V0−Vi的权值)<dist[Vi](i=2,4,5),那么就更新dist[Vi]的距离为dist[V0]+权值)。贪心:找出距离最短所代表的结点(这里索引其实就代表了结点,找的时候从没有标记过结点里面找): V 2 V_2 V2;更新
visit[1,0,1,0,0,0]
,标记 V 2 V_2 V2已经搜过 -
第二步:
找到 V 2 V_2 V2相连的边 V 3 V_3 V3,计算距离:
dist[0,inf,10,60,30,100]
( d i s t [ V 2 ] + 权 值 = 60 < d i s t [ V 3 ] = i n f dist[V_2]+权值=60<dist[V_3]=inf dist[V2]+权值=60<dist[V3]=inf)。贪心:找出距离最短所代表的结点: V 4 V_4 V4;更新
visit[1,0,1,0,1,0]
,标记 V 4 V_4 V4已经搜过。 -
第三步:
找出与 V 4 V_4 V4相连的边 V 3 , V 5 V_3,V_5 V3,V5,计算距离:
dist[0,inf,10,50,30,90]
( d i s t [ V 4 ] + 权 值 = 90 < d i s t [ V 5 ] = 100 dist[V_4]+权值=90<dist[V_5]=100 dist[V4]+权值=90<dist[V5]=100, d i s t [ V 4 ] + 权 值 = 50 < d i s t [ V 3 ] = 60 dist[V_4]+权值=50<dist[V_3]=60 dist[V4]+权值=50<dist[V3]=60)。贪心:找出距离最短所代表的结点: V 3 V_3 V3;更新
visit[1,0,1,1,1,0]
,标记 V 3 V_3 V3已经搜过 -
第四步:
找出与 V 3 V_3 V3相连的边 V 5 V_5 V5,计算距离:
dist[0,inf,10,50,30,60]
( d i s t [ V 3 ] + 权 值 = 60 < d i s t [ V 5 ] = 90 dist[V_3]+权值 = 60<dist[V_5]=90 dist[V3]+权值=60<dist[V5]=90)贪心:找出距离最短所代表的结点: V 3 V_3 V3;更新
visit[1,0,1,1,1,1]
,标记 V 5 V_5 V5已经搜过 -
计算结束
2.代码
/**
* 从一个结点出发,找寻最小路径对应的结点
* 思想: 利用已得到的顶点的最短路径来计算其它顶点的最短路径。
* 贪心算法: 利用局部最优来计算全局最优。
*
*
*/
public class Dij {
int k= 9; //结点个数
//贪心算法体现:找到每一次更新完dist距离数组内的最小值所代表的结点。注意是结点
int minDist(int[] dist, Boolean[] visit){
int min = Integer.MAX_VALUE,min_index = -1;
for (int i = 0; i < k; i++) {
if ( visit[i] == false && dist[i]<min) {
min = dist[i];
min_index = i;
}
}
return min_index;
}
int[] dijkstra(int graph[][],int src){
int dist[] = new int[k];
Boolean visit[] = new Boolean[k];
//初始化
for (int i = 0; i < k; i++) {
dist[i] = Integer.MAX_VALUE;
visit[i] = false;
}
//设置初始结点距离为0
dist[src] = 0;
for (int c = 0; c<k-1;c++){ //遍历k-1次,这样就得到了初始节点结点到所有结点的最短路径
int u = minDist(dist,visit); //第一次u是0
visit[u] = true; //代表已经搜过
//在这里对与u结点所有相连的边进行一次距离计算。值得注意的一点是,这里的dis[u]所存储的距离是0结点到u结点的距离
for (int v = 0; v < k; v++) {
if (visit[v]==false){ //没有搜过
//graph[u][v] !=0 存在边
if (graph[u][v] !=0 && dist[u]+graph[u][v]<dist[v]){ //&& dist[u]<Integer.MAX_VALUE感觉没必要加这一句
dist[v] = dist[u]+graph[u][v];
}
}
}
}
return dist;
}
public static void main(String[] args) {
int graph[][] = new int[][]{{0, 4, 0, 0, 0, 0, 0, 8, 0},
{4, 0, 8, 0, 0, 0, 0, 11, 0},
{0, 8, 0, 7, 0, 4, 0, 0, 2},
{0, 0, 7, 0, 9, 14, 0, 0, 0},
{0, 0, 0, 9, 0, 10, 0, 0, 0},
{0, 0, 4, 14, 10, 0, 2, 0, 0},
{0, 0, 0, 0, 0, 2, 0, 1, 6},
{8, 11, 0, 0, 0, 0, 1, 0, 7},
{0, 0, 2, 0, 0, 0, 6, 7, 0}};
Dij t = new Dij();
int dis[] = t.dijkstra(graph,0);
for (int i = 0; i < 9; i++) {
System.out.println(dis[i]);
}
}
}