图最短路径:dijkstra算法 、 spfa算法

dijkstra算法

  1. 对于一个权值非负的有向图,设有两个顶点集S,T;其中S集合中的顶点与源点的的最短已经求出。初始时S集合为空,T集合包含了所有的顶点。

  2. 设数组D,D[i]表示源点到点i的最短距离,初始时D内源点值为0,其他值为无穷大。

  3. 从T集合内选出最短距离最小的点,若找不到(T集合为空或者图不连通,有些点源点无法到达),则结束

  4. 若找到最小的点,则将其加入S集合中,然后用该点的D[i]其更新相邻的D,更新完成后 回到第三步。

package Graph;

public class Dijkstra {
	static int MAX = Integer.MAX_VALUE;
	static int[][] mp = new int[100][100]; //邻接矩阵
	static int[] D = new int[100];  //距离数组
	static int[] vis = new int[100]; //vis[i] = 1 表示i在S集合,为0表示i在T集合中
	static int n,m;   //n个顶点,m跳边。   
	static void dij(){
		for(int i=0;i<100;i++){
			D[i] = MAX;
		}
		D[1] = 0;  //源点距离为0
		while(true){
			int mini = 0,Min = MAX;
			for(int j=1;j<=n;j++){
				//找出T中最小的D[i]
				if(vis[j]==0 && D[j]<Min){
					mini = j; Min = D[j];
				}
			}
			if(mini == 0) return;
			vis[mini] = 1;
			//更新mini连通的顶点
			for(int j=1;j<=n;j++){
				if(D[j]>D[mini]+mp[mini][j]);
				D[j] = D[mini]+mp[mini][j];
			}
		}
	}
}

spfa算法

spfa算法同样可以用来计算单元最短路。它相比于dijkstra算法的有点在于可以计算包含负权边的图,并且可以判断是否存在负环。

算法思想:用一个队列来维护,初始时将源加入到队列中。每次出队一个元素,对所有该点可以到达的点进行松弛操作,若某相邻点松弛成功,则将其入队。队列为空时算法结束。

这篇文章写的十分详细:https://blog.csdn.net/qq_36313726/article/details/79290927?biz_id=102&utm_term=spfa%E7%AE%97%E6%B3%95&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-1-79290927&spm=1018.2118.3001.4187

采用前向星的实现:

package Graph;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;

public class Spfa {
	static int maxn = 1000001;
	class Edge{
		int d;   //边权值
		int to;  //连接的下一个顶点
		int next; //上一条边
		Edge(int d,int to,int next){
			this.d = d;
			this.to = to;
			this.next = next;
		}
	}
	static Edge[] graph = new Edge[maxn];   //存所有的边
	static int n;  // 顶点数
	static int m;   // 边数
	static int[] head = new int[maxn];   //head[u]表示u起始的最大边的编号
	static int num=0;    //
	static int[] vis = new int[maxn];  //  判断是否在队列中
	static int[] D = new int[maxn];  //   距离数组,除源点外,其余点初始化为无穷大
	
	void add(int u,int v,int dis){   //增加一条边
		graph[num] = new Edge(dis,v,head[u]);
		head[u] = num++;
	}
	
	static void spfa(){
		Arrays.fill(D, Integer.MAX_VALUE);
		Queue<Integer> q = new LinkedList<Integer>();
		D[1] = 0;
		q.offer(1);
		while(!q.isEmpty()){
			int u = q.poll();
			vis[u] = 0;
//			cnt[u]++;
//			if(cnt[u] > n){
//				//存在负环;
//				return;
//			}
			for(int i=head[u]; i!=-1;i=graph[i].next){
				int v = graph[i].to;
				if(D[v] > D[u]+graph[i].d){  //松弛
					D[v] = D[u]+graph[i].d;
					if(vis[v]==0){  //松弛成功,若v没有在队列中,则入队
						vis[v] = 1;
						q.offer(v);
					}
				}
			}
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值