求有權圖和無權圖的最短路徑


無權圖的最短路徑

思路:無權圖的最短路徑也就是要求兩點之間最少幾跳可達,那么我們可以這樣,用廣度遍歷,從起點開始一層層遍歷,如果第一次遍歷到終點,那么肯定是最短路徑。

 
	public static void findPath(int start,int end)
	{
		//創建一個隊列來存儲
		LinkedList< VNode> queue=new LinkedList<VNode>();
		queue.offer(nodes[start]);
		
		
		while(!queue.isEmpty())
		{
			VNode vnode=queue.peek();
			isVisit[vnode.index]=true;
			BNode bnode=vnode.bnode;
			//如果結束點已經訪問 跳出循環
			if(isVisit[end])
				break;
			//如果他的鄰節點都訪問或者沒有鄰節點 跳出循環
			while(bnode!=null)
			{
				//如果鄰節點還沒被訪問訪記錄他的上一節點,否則不進行記錄。這樣的話即使到了下一跳有這個頂點,記錄的也是更的短路徑,比如說起點A 鄰節點有BCD B的鄰節點是C,此時遍歷A的鄰節點C的時候,就記錄C的上一節點是A,下次遍歷B的領節點,因為C已經被訪問,所以C記錄的上一節點還是A,這樣就保證了最短路徑。
				if(!isVisit[bnode.index])
				{
					
					//用於記錄路徑
					nodes[bnode.index].before=vnode;
					queue.offer(nodes[bnode.index]);
					isVisit[bnode.index]=true;
				}
				bnode=bnode.next;
			}
			queue.pop();
		}
	}
	public static void printPath(int end)
	{
		VNode node=nodes[end];
		int count=0;
		String path="";
		while(node!=null)
		{
			
			path=node.index+path;
			node=node.before;
			count++;
		}
		System.out.println(path+"長度為:"+(count-1));
	}

Dijkstra求有權圖最短路徑

Dijkstra思路:依次找到最短路徑,比如起點A,先找到距離A路徑最短的點,比如B,AB路徑長為1,這時候,接着往下找比大於等於1的最短路徑。通俗講就是小明很貪心,每一次都找挑最短路徑。


import java.util.Scanner;

public class Dijkstra {
	
	public static void main(String[] args) {
		final int MAX=Integer.MAX_VALUE;
		Scanner in=new Scanner(System.in);
		int vNum=in.nextInt();
		int edgeNum=in.nextInt();
		//二維數值用來表示圖
		int graphic[][]=new int [vNum][vNum];
		//flag[v][w]標識 從v0到v點 w是不是在路徑上,用於記錄路徑
		boolean [][] path=new boolean [vNum][vNum];
		//標識是否訪問過
		boolean [] isVisit=new boolean[vNum];
		//v0到各點的最短路徑
		int distance[]=new int [vNum];
		//進行初始化,任意兩個點的距離無限大
		for (int i = 0; i <vNum; i++) {
			for (int j = 0; j < vNum; j++) {
				graphic[i][j]=MAX;
			}
		}
		//讀取數據,設置權值
		for (int i = 0; i < edgeNum; i++) {
			graphic[in.nextInt()][in.nextInt()]=in.nextInt();
		}
		//起點
		int v0=in.nextInt();
		//結束點
		int end=in.nextInt();
		in.close();
		//進行初始化
		isVisit[v0]=true;
		for (int i = 0; i < distance.length; i++) {
			distance[i]=graphic[0][i];
			if(graphic[v0][i]<MAX)
			{
				path[i][i]=true;
				path[i][v0]=true;
			}
		}
		int v=-1;
		//要找到vNum-1個頂點,循環次數為vNum-1
		for (int i = 1; i < vNum; i++) {
			int min=Integer.MAX_VALUE;
			//遍歷找到目前v0到其他點的最短距離的點,依次找到離起點最近的點
			for (int j = 0; j < vNum; j++) {
				if(!isVisit[j]&&distance[j]<min)
				{
					min=distance[j];
					v=j;
				}
			}
			isVisit[v]=true;
			//新的點v加入,重新更新從v0到其他點的最短距離
			for (int k = 0; k < distance.length; k++) {
				if(!isVisit[k]&&graphic[v][k]<MAX&&distance[k]>min+graphic[v][k])
				{
					distance[k]=min+graphic[v][k];
					//當前的路徑是從v到w,所以到v0到v的最短路徑上的點也是v0到w上的點
					System.arraycopy(path[v], 0, path[k], 0, path[v].length);
					path[k][k]=true;
				}
			}
		}
		System.out.print("路徑為:");
		for (int i = 0; i < vNum; i++) {
			if(path[end][i])
				System.out.print(i+" ");
		}
		System.out.println("路徑長為"+distance[end]);
	}
	
	
	
	
}

測試數據:
6 8
0 4 30
0 2 10
0 5 100
1 2 5
2 3 50
4 5 60
4 3 20
3 5 10
0 3
輸出:
路徑為:0 3 4 路徑長為50

Floyd算法求有權圖最小路徑

Floyd思路:floyd算法用的dp的思想,核心代碼

	for (int k = 0; k < vNum; k++) {
		if(distance[i][j]>distance[i][k]+distance[k][j])
		{
			distance[i][j]=distance[i][k]+distance[k][j];
			index=k;
		}
	}

求i到j的最短路徑,通過遍歷每一種情況,從i跳到k再有k跳到j,遍歷每一個可能的k值,最后求得到最小路徑。

import java.util.Scanner;

public class Floyd {
	public static void main(String[] args) {
		final int MAX=10000;
		Scanner in=new Scanner(System.in);
		int vNum=in.nextInt();
		int edgeNum=in.nextInt();
		//二維數值用來表示圖
		int distance[][]=new int[vNum][vNum];
		int [][] path=new int [vNum][vNum];

		//進行初始化,任意兩個點的距離無限大
		for (int i = 0; i <vNum; i++) {
			for (int j = 0; j < vNum; j++) {
				distance[i][j]=MAX;
				if(i==j)
					distance[i][j]=0;
			}
		}
		//讀取數據,設置權值
		for (int i = 0; i < edgeNum; i++) {
			distance[in.nextInt()][in.nextInt()]=in.nextInt();
		}
		//起點
		int v0=in.nextInt();
		//結束點
		int end=in.nextInt();
		in.close();
		
		for (int i = 0; i < vNum; i++) {
			for (int j = 0; j <vNum; j++) {
				int index=i;
				for (int k = 0; k < vNum; k++) {
					if(distance[i][j]>distance[i][k]+distance[k][j])
					{
						distance[i][j]=distance[i][k]+distance[k][j];
						index=k;
					}
				}
				path[i][j]=index;
			}
			
		}
		System.out.println("最短路徑長為:"+distance[v0][end]);
		System.out.print("路徑為:"+end+" ");
		while(true)
		{
			if(end==v0)
				break;
			System.out.print(path[v0][end]+" ");
			end=path[v0][end];
			
		}
		
	}
}

測試數據:
6 8
0 4 30
0 2 10
0 5 100
1 2 5
2 3 50
4 5 60
4 3 20
3 5 10
0 3
輸出:
最短路徑長為:50
路徑為:3 4 0

我覺得分享是一種精神,分享是我的樂趣所在,不是說我覺得我講得一定是對的,我講得可能很多是不對的,但是我希望我講的東西是我人生的體驗和思考,是給很多人反思,也許給你一秒鍾、半秒鍾,哪怕說一句話有點道理,引發自己內心的感觸,這就是我最大的價值(這是我喜歡的一句話,也是我寫博客的初衷)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM