最短路径(Dijkstra、Floyd)

与最小生成树学习相比,一开始我有点昏了。感觉既然都能计算出 “最短” 路径,为什么还要专门的研究最短路径的Dijkstra,Floyd呢?


后来才知道,最小生成树是保证这个图的所有路径加起来最短!


而最短路径保证A点到B的路径最短,并不能保证这个图的路径最短!


Dijkstra:


狄克斯特拉算法,这个算法,我到现在都感觉跟Prim算法有一些相同之处。


他们都是一开始按照起始点,保存起始点所能达到的点的距离。


然后从中找出一个最近的点k,然后再根据点k所能到达的A点的距离更新原先起始点所能到达的A点的距离,前提起始点到K点再到A点的距离小于起始点直接到达A点的距离


我想着两个算法有两个区别 :1、Prim是只要已经连通的点中,假设k点,k点到A点的距离小于原先已更新的到达A点的最短距离,那就更新lowcost

    Kruscal则是,K点到A点的距离小于起始点到达A点的距离,则更新

     2、Prim对于已经确定加入S集合的点,根据之后所能到达的点跟已经加入S点的距离相比,如果比之前的最短距离还小,还会重新将其从S集合中拿出(即重新规划路线)

Kruscal则是已经确定加入S集合的点,就不会再将其从S集合中拿出来了

原因是:Prim查找的最近距离K点,是已经加入S集合中某个点距离K点距离最短即可

Kruscal则是距离起始点最近的点,才能作为K点,所以之后找到的肯定都是大于之前的距离的,亦或是原先起始点到达不了的点,想要到达这个点必须经过之前的点,所以距离怎么都不会比之前的短。



public class Dijkstra {
	
	private final int INF = 32767;

	void Shorted_Path(MGraph g,int v){
		
		int s[] = new int[g.n];//保存点是否已经加入集合S,0未加入,1加入
		int dist[] = new int[g.n];//保存v点到其他点的距离
		int path[] = new int[g.n];//保存v点到达该点的前一个点编号
		
		for(int i = 0 ; i < g.n ; i ++){
			
			s[i] = 0;//表示没有放入S集合中
			dist[i] = g.edges[v][i];
			path[i] = v;
			
		}
		
		s[v] = 1;//v已经放入集合S中
		path[v] = 0;//且上一个点不存在
		
		for(int i = 1 ; i < g.n ; i ++){//查找到剩下n-1个点的距离

			int min = 32767;
			int k = 0;
			for(int j = 0 ; j < g.n ; j ++){
				
				if (s[j] == 0 && dist[j] < min) {
					
					min = dist[j];
					
					k = j;
					
				}
				
			}
			
			s[k] = 1;
			
			for(int j = 0 ; j < g.n ; j ++){//更新dist和path,修改不在s中的顶点的距离
				
				if (s[j] == 0) {
					
					if (g.edges[k][j] < INF && g.edges[k][j] + dist[k] < dist[j]) {
						
						dist[j] = g.edges[k][j] + dist[k];
						
						path[j] = k;
						
					}
					
				}
				
			}
			
		}
		
		Dispath(s,dist,path,v,g.n);//输出路径
		
	}
	
	private void Dispath(int[] s,int[] dist,int[] path,int v,int n){
		
		for(int i = 0 ; i < n ; i ++){
			
			if (s[i] == 1) {
				
				System.out.println("起始点:"+v);
				
				System.out.println("终止点:"+i);
				
				System.out.println("最短路径:"+dist[i]);

				Ppath(path, i, v);
				
			}
			
		}
		
	}
	
	private void Ppath(int[] path, int i,int v){
		
		int k = path[i];
		
		if (k == v) return;
		
		Ppath(path, k, v);
			
		System.out.println(k+",");
		
		
	}
	
}



Floyd:


弗洛伊德算法:这个算法第一次接触还是大一参加ACM的时候,那个时候蛮喜欢的,因为简单易记!三重循环就好了!


原理:对于每两个点,都遍历所有的点作为中间点搭桥,判断出最短的距离,其他的点亦可以在这个这两个点的基础上判断出最短距离


public class Floyd {

	private final int INF = 32768;
	private final int MAX = 100;
	
	public void Shortest_Path(MGraph g){
		
		int A[][] = new int[g.n][g.n];
		int path[][] = new int[g.n][g.n];
		
		for(int i = 0 ; i < g.n ; i ++){
			
			for(int j = 0 ; j < g.n ; j ++){
				
				A[i][j] = g.edges[i][j];
				path[i][j] = -1;//表示没有经过任何中间点;
				
			}
			
		}
		
		for(int k = 0 ; k < g.n ; k ++){
			
			for(int i = 0 ; i < g.n ; i ++){
				
				for(int j = 0 ; j < g.n ; j ++){
					
					if (A[i][j] < A[i][k] + A[k][j]) {
						
						A[i][j] = A[i][k] + A[k][j];
						path[i][j] = k;
						
					}
					
				}
				
			}
			
		}
		
		Dispath(A,path,g.n);
		
	}

	private void Dispath(int[][] a, int[][] path, int n) {
		
		for(int i = 0 ; i < n ; i ++){
			
			for(int j = 0 ; j < n ; j ++){
				
				if (a[i][j] == INF) {
					
					if (i != j) {
						System.out.println("从"+i+"到"+j+"没有路径");
					}
					
				}else{
					
					System.out.println("从"+i+"到"+j+"的距离为:"+a[i][j]);
					System.out.println("路径为:"+i);
					Ppath(path,i,j);
					System.out.println(","+j);
					
					
				}
				
			}
			
		}
		
	}

	private void Ppath(int[][] path, int i, int j) {

		if (i == j) return;
		
		int k = path[i][j];
		Ppath(path, i, k);
		System.out.println(","+k);
		Ppath(path, k, j);
		
	}
	
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值