0
点赞
收藏
分享

微信扫一扫

(更新完善版)堆优化dijkstra与spfa算法解决无负权回路单源最短路问题

Sikj_6590 2022-02-17 阅读 36

启动:

系统学习最短路算法之无负权回路单源最短路算法:

堆优化版本dijkstra()–>java语言版

铺垫知识:

知识点(1):邻接表
e[],ne[],h[],idx,w[];

static void add(int a,int b,int c){
	e[idx]=b;
	ne[idx]=h[a];
	w[idx]=c;
	h[a]=idx++;
}
//知识点随后补充到博客
知识点(2):小根堆
static class PII{
	int num;//节点编号
    int distance;//节点和目标节点间的距离
    PII(int num,int distance){
        this.num=num;
        this.distance=distance;
    }
}
PriorityQueue <PII> aq=new PriorityQueue<>(Comparator.comparing(PII->PII.distance));//小根堆,类排序

算法过程:

整体思路:
算法流程:
  1. 初始化处理,邻接表头数组h(初始化为-1 ),距离数组dist(初始化为无穷大)
  2. 将源点的序号和距离一起(通过新建类实现)加入优先队列中
  3. 在队列不为空的前提下,抛出表头元素,并将其状态标记为true(表示已经使用过了)
  4. 用表头元素更新与它直接相连的点,并将其加入优先队列中
  5. 结束之后判断是否能够到达目标节点,若可以直接返回,不可以返回题目给定内容
鸡汤来喽(代码部分)
//之前记得定义全局变量......
public static int dijkstra(){
	PriorityQueue<PII> aq=new PriorityQueue<>(Comparator.comparing(PII->PII.distance));//建立优先队列
	dist[1]=0;//源点为1号节点,距离为0,其余dist为0x3f3f3f3f表示无穷大
	aq.add(new PII(1,0));//将新节点加入队列中
	while(!aq.isempty()){
		PII temp=aq.poll();
		int num=aq.num;
		int distance=aq.distance;
		if(st[num]==true)continue;//如果用这个点更新过其他节点,那么就直接略过!
		st[num]=true;//标记当前使用的节点,之后不再使用
		for(int i=h[num];i!=-1;i=ne[i]){//用当前节点,更新其他与其直接相连的节点
			int j=e[i];
			if(dist[j]>dist[num]+w[i]){
				dist[j]=dist[num]+w[i];
                aq.add(new PII(j,dist[j]));//将刚刚更新过的节点加入优先队列中
			}
		}
	}
    if(dist[n]==0x3f3f3f3f)return -1;//目标节点若为初始化的无穷大,则表示无法到达
    return dist[n];
     
}
public static void main(String[] args) {
//这里面已经将表建好,并且初始化了h数组和dist数组
}

队列优化版本spfa()–>java语言版

铺垫知识:

算法过程:

整体思路:
算法流程
  1. 初始化处理,邻接表头数组h(初始化为-1 ),距离数组dist(初始化为无穷大)
  2. 将源点的序号加入队列中,并将其标记为true
  3. 在队列不为空的前提下,抛出表头元素,并将其状态标记为false
  4. 用表头元素更新与它直接相连的点,若发生跟新则将其加入队列中,并将状态改为true
  5. 结束之后判断是否能够到达目标节点,若可以直接返回,不可以返回题目给定内容
鸡汤又来喽(代码部分)
//之前记得定义全局变量......
public static void spfa(){
    dist[1]=0;
    Queue<Integer> q=new LinkedList<>();
    q.add(1);//将源点加入队列
    st[1]=true;//将状态改为使用过
    while(!q.isempty()){
        int t=q.poll();
        st[t]=false;//从队列中抛出后,将状态改为未使用过
        for(int i=h[t];i!=-1;i=ne[i]){
            int j=e[i];
            if(dist[j]>dist[t]+w[i]){
				dist[j]=dist[t]+w[i];
                if(!st[j]){//判断更新过后的节点是否在队列中,若不存在则加入队列,并将其状态改为true
					q.add(j);
                    st[j]=true;
                }
            }	
        }
    }
     
}
public static void main(String[] args) {
//这里面已经将表建好,并且初始化了h数组和dist数组
}

总结:

  • dijkstra与spfa中st[]数组的作用是不一样的,dijkstra中st数组具有单调性,而spfa中st数组不具备单调性

  • 记得初始化h数组和dist数组,有时候写题写顺手了,好像很自然就忘记初始化了

  • spfa从队列中使用了当前的点,会把该点pop掉,状态数组st[i] = false(说明堆中不存在了) ,更新临边之后,把临边放入队列中, 并且设置状态数组为true,表示放入队列中 。如果当前的点距离变小,可能会再次进入队列,因此可以检验负环:

举报

相关推荐

0 条评论