一个简单的模板,需要注意的是当权值不存在或者权值都相同时,dijkstra算法变成bfs,而且dijkstra算法处理不了负权边情况。
一个重要的区别:(dijkstra与prim的区别)
在dij算法中dis[i]数组表达的意义是:节点i到源点start最短距离,松弛操作dis[i]>dis[t]+map[t][i](t节点是最新确定的最短路径节点,i节点既是t的一个邻接节点)的意义是:t的邻接节点i到源点start的最小距离(dis[i]),是否大于 最新节点t到原点的最短距离(dis[t])+节点t与节点i的权值(map[t][i]),这一过程都在围绕dis[i]数组进行。
在prim算法中dis[i]数组表达的意义是:节点i到 任意mst'节点' 的最小距离,dis[i]>x[t][i],(i为任意的未访问过的节点,t为最新的mst节点)意思是如果i节点到mst节点的距离要 大于 最新的mst节点t和i节点的权值,那么很显然为了满足总权值最小一定会有dis[i]=x[t][i]。
输出个点到原点的最短距离
第一行的数是源点,第二行的数是节点个数,第三行的数是边数
接下来的分别是初始节点,结束节点,和权值
测试用例:
1
5
7
1 2 2
1 3 3
2 3 5
2 4 6
3 4 7
3 5 1
4 5 4
答案:
0
2
3
8
4
import java.util.ArrayList;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;
public class 单源点最短路_Dijkstra算法 {
/**
* 应用优先队列优化dijkastra解决单源点最短路径问题
* @param args
*/
static class node{
public int nod;//节点标号
public int sum;//当前nod节点到源点的最小的距离
node(int nod,int sum){
this.nod=nod;
this.sum=sum;
}
}
//邻接表节点
static class edge{
public int a;//起始节点
public int b;//结束节点
public int w;
edge(int a,int b,int w){
this.a=a;
this.b=b;
this.w=w;
}
}
static final int INF=Integer.MAX_VALUE;
static int vis[];//标记数组
static int dis[];//dis[i]的意义是节点i到 源点 的最短路径,整个过程就是在维护这个数组
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int start=sc.nextInt();//起始点位置
int n=sc.nextInt();//图的节点个数
int m=sc.nextInt();//边数
// sc.nextLine();
// int map[][]=new int[n+1][n+1];//邻接矩阵
//初始化邻接矩阵都为INF
// for (int i = 0; i < map.length; i++) {
// for (int j = 0; j < map[0].length; j++) {
// map[i][j]=INF;
// }
// }
//邻接表
ArrayList<edge>[] map=new ArrayList[n+1];
for (int i = 0; i < map.length; i++) {
map[i]=new ArrayList<edge>();
}
//将数据录入邻接矩阵
for (int i = 0; i < m; i++) {
int a=sc.nextInt();
int b=sc.nextInt();
int w=sc.nextInt();
map[a].add(new edge(a,b,w));
//邻接矩阵方法
// map[a][b]=Math.min(map[a][b],w);//可能会有两个节点间存在两条路径,总是选取最小的那条
}
//执行算法
dijkstra(start,map,n,m);
for (int i = 1; i < dis.length; i++) {
System.out.println(dis[i]);
}
}
/**
*
* @param start 初始节点
* @param map 邻接矩阵
* @param n 节点数量
* @param m 边的数量
*/
private static void dijkstra(int start, ArrayList<edge>[] map, int n, int m) {
//重写comparator方法,规定队列中小的数优先出队
Comparator<node> com=new Comparator<node>(){
@Override
public int compare(node o1, node o2) {
int num1=o1.sum;
int num2=o2.sum;
if(num1>num2){
return 1;
}else if (num1<num2) {
return -1;
}else {
return 0;
}
}
};
//定义优先队列,初始值为11,比较器为com
Queue<node> q=new PriorityQueue<node>(11,com);//初始化优先队列
q.offer(new node(start,0));//初始节点入队
vis=new int[n+1];//初始化 标记表
dis=new int[n+1];//初始化 各节点到源点的最小距离表
//都初始化为INF
for (int i = 0; i <= n; i++) {
dis[i]=INF;
}
//start节点到自身的距离为0
dis[start]=0;
while (q.size()!=0) {//当优先队列不为空时
node temp=q.poll();//弹出并删除队列头结点
int t=temp.nod;//提取头节点下表数
if(vis[t]==1){//如果该节点已经被访问过了,直接跳过这次循环
continue;
}
vis[t]=1;//没有访问过,标记访问过
//遍历所有t的邻接节点
for (int i = 0; i < map[t].size(); i++) {
//如果该节点没有被访问过,且,tempnode到能够到达该节点(邻接)
if(vis[map[t].get(i).b]==0 && map[t].get(i).w<INF){
//松弛操作,更新dis表,如果这个邻接节点map[t].get(i).b到原地的距离要 大于 当前节点t到原点的距离+t节点到他的邻接点map[t].get(i).b 的距离之和
if(dis[map[t].get(i).b]>dis[t]+map[t].get(i).w){
dis[map[t].get(i).b]=dis[t]+map[t].get(i).w;//更新邻接点map[t].get(i).b到远点的距离
q.offer(new node(map[t].get(i).b,dis[map[t].get(i).b]));//将更新的节点压入优先队列
}
}
}
}
}
}