package ccf;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;
public class PriorityQueueDijstra {
/**
* 应用优先队列优化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[b].add(new edge(b,a,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; //返回1代表num1在后,即大数在后,从小到大排序
}else if (num1<num2) {
return -1; //返回-1代表num1在前,即小数在前,从小到大排序
}else {
return 0; //返回0 表示位置不变
}
}
/***
*
* public int compare(node o1, node o2) {
int num1=o1.sum;
int num2=o2.sum;
if(num1<num2){
return 1; //返回1代表num1在后,即小数在后,从大到小排序
}else if (num1>num2) {
return -1; //返回-1代表num1在前,即大数在前,从大到小排序
}else {
return 0; //返回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]));//将更新的节点压入优先队列
}
}
}
}
}
}
在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]数组进行。在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]数组进行。
原文:https://blog.csdn.net/qq_39020387/article/details/79979543