迪杰斯特拉算法
迪杰斯特拉算法同样也是基于贪婪思想来的,这也是一个图论方面计算最短路径的算法
问题描述
如下图所示,求从1到其他每个点的最短路径
解决流程
- 我们定义一个数组,表示1这个点到其他的点的所有最短距离。
开始我就在第1这个点,INF表示无法抵达(距离无穷大)
- 贪心选择
比如我想通过1到其他的点。如果要产生一个中间点就可以到其他的点,那么我找离我最近的那个点走就一定能到最短的路。
那么我们就应该找离1最近的那个点去中转,显然我应该找到3。
那么3加入我们能走的点此时我们已经有1和3两个点,松弛,加进来的这个点我们去判断他能走的路径和之前存的距离相比较。可以看到3到4的距离是50,而1到3的距离是10,那么1到4的距离就是60,这也显然比INF小,自然改变表上1到4的距离,同时记录路径。
其他的点也是同样的操作,如果距离更近就更改,否则就保持原样。
表中红色的点表示已经找过的点
- 重复上面的步骤继续找离最短的点
很显然是找到5这个点,考虑5加进来到4这个点:最开始不加进来5的时候是60,加进来,我们发现5可以到4 距离为20,1到5是30此时30+20=50<60
接下来继续找离1最近的点,很显然是4,因为我们4通过中转到的,加入4进来。4可以到6这点 距离为10,我们看从1到4的最短距离为50那么 1-6 可以变成50+10=60 < 90所以更新为60。
接下来加6,6也不存在可抵达的点,所以表中的值也无需更新
- 直到表中的距离都加过时(除INF外),就表示加完了,此时表中的数据就是1到各个点的最短距离。
代码
public class Dijstarl {
public static void main(String[] args) {
int n , m , x; //n表示n个点,m表示m条边。x表示要求最短路径的点
Scanner cin = new Scanner(System.in);
n = cin.nextInt();
m = cin.nextInt();
x = cin.nextInt();
//距离为了方便我就用数组了
int value[][] = new int[n+1][n+1]; //表示n个点之间的权重 地图用的是邻接表 因为点太多了
int dis[] = new int[n+1]; //表示存从x点到每个点的最短路径的
//先初始化图。最开始都认为没有可以走的边
for(int i=1;i<=n; i++) {
dis[i] = Integer.MAX_VALUE; //最开始没有最短距离 都是无穷大 也可以用-1表示
for(int j =1; j<=n ;j++) {
if(i == j) value[i][j] = 0 ; //表示是自己
else value[i][j] = -1; //表示从i到j最开始是没有路的
}
}
//接下来输入这个图上面的所有边
for(int i=1;i<=m;i++) {
int a = cin.nextInt();
int b = cin.nextInt();
int weight = cin.nextInt(); //表示 a点到b点的距离为weight
value[a][b] = weight;
//在这里的时候就可以计算出要求最短路径的第一个点,因为第一个点进来就是直达就行了
if(a == x) { //表示是我们要求的那个点
dis[b] = weight;
}
}
dijkstra(x, dis, value, n);
}
public static void dijkstra(int x,int dis[],int value[][],int n) {
boolean mark[] = new boolean[n+1]; //标记是不是已经加入过了
for(int i = 1;i<=n;i++) {
mark[i] = false; //最开始是没有加的
}
dis[x] = 0;
mark[x] = true;
while(true) { //如果每次都有点加进来 不是O(N) Nlogn
//找离最近的那个点
int min = Integer.MAX_VALUE;
int loc = -1; //存储最小的那个点
for(int i =1; i<= n;i++) { //O(n)
if(!mark[i] && dis[i] < min) {
min = dis[i];
loc = i;
}
}
if(loc == -1)break;
mark[loc] = true;
for(int i = 1; i <= n;i++) {
if(value[loc][i] != -1) { //判断我们加进来的这个点能不能到i
if(dis[loc] + value[loc][i] < dis[i]) { //通过中转点能不能减少距离
dis[i] = dis[loc] + value[loc][i];
}
}
}
}
System.out.println(x + "点到每个点的最短距离如下所示:");
for(int i = 1 ; i <= n;i++) {
if(dis[i] != Integer.MAX_VALUE) {
System.out.println("到" + i + "点的最短距离为:" +dis[i]);
}else{
System.out.println("不能到达" + i);
}
}
}
}