Dijkstra(迪杰斯特拉)算法刷题模板(附详细注释)及经典例题 - java语言

dijkstra的题目一般给出每条边的起点、终点、权值,需要转化成邻接矩阵或邻接表
邻接矩阵的时间复杂度为O(v^2),
邻接表的时间复杂度为O(v^2+E)
dijkstra算法用于求单源最短路径,即某个顶点到其他所有顶点的最短路径。
dijkstra算法不适用于存在负权值的边的情况。
与《算法笔记》中另用数组d[]表示起点到各点的最短路径不同,本模板直接在原来的邻接矩阵中修改G[s][i],执行完dijkstra算法后,G[s][i]即为起点到各点的最短路径

dijkstra算法经典例题:

输入顶点数n、边数e、起始顶点s,下面e行为每条边的起点、终点、权值
输出起点s到所有顶点的最短路径、起点s到所有顶点的距离

样例1:
输入:
5 7 0
0 1 10
0 3 30
0 4 100
1 2 50
2 4 10
3 2 20
3 4 60

输出:
从0出发到0的最短路径为:0
从0出发到1的最短路径为:0 1
从0出发到2的最短路径为:0 3 2
从0出发到3的最短路径为:0 3
从0出发到4的最短路径为:0 3 2 4
0 10 50 30 60

样例1的邻接矩阵:
static int[][] w = {
{0,10,M,30,100},
{M,0,50,M,M},
{M,M,0,M,10},
{M,M,20,0,60},
{M,M,M,M,0}
};

样例2:
输入:
//6个顶点,8条边,起点为0号顶点。以下8行为8条边
//边0->1的边,权为1,下同
6 8 0
0 1 1
0 3 4
0 4 4
1 3 2
2 5 1
3 2 2
3 4 3
4 5 3

输出:
从0出发到0的最短路径为:0
从0出发到1的最短路径为:0 1
从0出发到2的最短路径为:0 1 3 2
从0出发到3的最短路径为:0 1 3
从0出发到4的最短路径为:0 4
从0出发到5的最短路径为:0 1 3 2 5
0 1 5 3 4 6

import java.util.*;
public class Dijkstra模板 {
	
	static int MAXV=999;					//最大顶点数,由具体题目决定
    static int M=999999;					//不能用Integer.MAX_VALUE,否则做加法后可能会溢出
	  
	static int n,m,s;  						//n为顶点数,m为边数,s为起始顶点编号
	static int[][] G=new int[MAXV][MAXV];  	//一个有向图的邻接矩阵,
//与《算法笔记》中另用数组d[]表示起点到各点的最短路径不同,
//本模板直接在原来的邻接矩阵中修改G[s][i],执行完dijkstra算法后,G[s][i]即为起点到各点的最短路径

	static int[] v=new int[MAXV];    		//标记数组,v[i]=1表示i点已访问,初值均为0
	
	static String[] path=new String[MAXV]; 	//存放从start到其他各点的最短路径的字符串表示  
	
	//除了距离之外的第二标尺
//	static int cost[][]=new int[MAXV][MAXV]; cost代表新增的边权
//	static int c[]=new int[MAXV];            c代表从起点到各点的花费
	
//	static int resource[]=new int[MAXV];     resource代表新增的点权
//	static int r[]=new int[MAXV];		     r代表从起点到各点获得的资源
	
//	static int num[]=new int[MAXV];          num代表到各点的最短路径条数。
	
    public static void main(String[] args) {  
		Scanner sc=new Scanner(System.in);
		n=sc.nextInt();
		m=sc.nextInt();
		s=sc.nextInt();

		for(int i=0;i<n;i++) {
			Arrays.fill(G[i], M);
			G[i][i]=0;
			path[i]=s+""; 
		} 
             
//      Arrays.fill(c, M);
//      c[s]=0;
//      r[s]=resource[s];
//      num[s]=1;

		for(int i=0;i<m;i++) {
			int v1=sc.nextInt();
			int v2=sc.nextInt();
			int weight=sc.nextInt();
//			int co=sc.nextInt();
			G[v1][v2]=weight;
//			G[v2][v1]=weight;  若为无向图,则加上这一句
//			cost[v1][v2]=co;
//			cost[v2][v1]=co;
		}
        
		dijkstra(s);

        for(int i=0;i<n;i++) {
            System.out.println("从"+s+"出发到"+i+"的最短路径为:"+path[i]);    
        }
		
		for(int i=0;i<n;i++) {
			System.out.print(G[s][i]+" ");
		}
		
		sc.close();
    }
    
    
	//dijkstra算法
    public static void dijkstra(int s){  
     //接受一个起点编号s(从0开始编号)  

        for(int i=0;i<n;i++)  //要加入n个顶点  
        {  
          //1、选出一个距离初始顶点s最近的未标记顶点  u、从s到u的距离min
            int u=-1;    
            int min=M;  
            for(int j=0;j<n;j++) {  
                if(v[j]==0&&G[s][j]<min) {  
                    min=G[s][j];  
                    u=j;  
                }
            }
            
            
          //2、选好u之后,看看u是否存在,若存在则更新状态
          //若剩下的顶点都和起点s不连通,则u=-1,返回
            if(u==-1) return ;
          //将第i个选出的顶点u标记为已求出最短路径
            v[u]=1;  
            
            
          //3、以u为中间点,修正从【起点s】到未访问各点的距离  
			for(int j=0;j<n;j++) {
				if(v[j]==0) {
					if(G[s][u]+G[u][j]<=G[s][j]) {	//要求path时,必须写成“<=”,否则可以只写“<”
						G[s][j]=G[s][u]+G[u][j];
					
						//这里进行其他某些操作
						path[j]=path[u]+" "+j;
//						c[j]=c[u]+cost[u][v];
//						r[j]=r[u]+resource[j];
//						num[j]=num[u];
				}
//若上个if条件中符号为"<",且存在第二标尺,那么还要另外考虑第一标尺相同时的情况
//					else if(G[s][u]+G[u][j]==G[s][j]) {
//					    if(当前的第二标尺优于之前){
//						path[j]=path[u]+" "+j;
//				}
//						c[j]=Math.min(c[j],c[u]+cost[u][v]);
//						r[j]=Math.max(r[j],r[u]+resource[j]);
//						num[j]+=num[u];
//					}
				}
			}
        }
    }
}

熟练掌握了dijkstra模板并且会做简单题之后,我们来做一下下面这两道难度较大的dijkstra算法的题目,其实可以可以看出来,难题一般都是在经典例题的基础上改编的。
下面两题都是PAT甲级考试的真题,原题即为英文,套用上文中的dijkstra算法模板给出了java代码的答案

下面这道题添加了两个第二标尺:最短路径数量num,每个城市的资源(救援队)resource

PAT A1003 Emergency (25分)

原文链接:PAT A1003 Emergency
As an emergency rescue team leader of a city, you are given a special map of your country. The map shows several scattered cities connected by some roads. Amount of rescue teams in each city and the length of each road between any pair of cities are marked on the map. When there is an emergency call to you from some other city, your job is to lead your men to the place as quickly as possible, and at the mean time, call up as many hands on the way as possible.

Input Specification:
Each input file contains one test case. For each test case, the first line contains 4 positive integers: N (≤500) - the number of cities (and the cities are numbered from 0 to N−1), M - the number of roads, C​1and C​2 - the cities that you are currently in and that you must save, respectively. The next line contains N integers, where the i-th integer is the number of rescue teams in the i-th city. Then M lines follow, each describes a road with three integers c​1 , c​2 and L, which are the pair of cities connected by a road and the length of that road, respectively. It is guaranteed that there exists at least one path from C​1​​ to C​2​​ .

Output Specification:
For each test case, print in one line two numbers: the number of different shortest paths between C
​1 and C​2​​ , and the maximum amount of rescue teams you can possibly gather. All the numbers in a line must be separated by exactly one space, and there is no extra space allowed at the end of a line.

Sample Input:
5 6 0 2
1 2 1 5 3
0 1 1
0 2 2
0 3 1
1 2 1
2 4 1
3 4 1

Sample Output:
2 4

下图为《算法笔记》379页,对此题的解析
在这里插入图片描述

import java.util.*;
public class PAT_A1003_Emergency {
	
	static int M=100000000;
	static int MAXN=999;
	
	static int n;
	static int[][] G=new int[MAXN][MAXN];
	static int[] v=new int[MAXN];
	static int[] resource=new int[MAXN];
	static int[] r=new int[MAXN];
	static int[] num=new int[MAXN];
	
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		n=sc.nextInt();
		int m=sc.nextInt();
		int c1=sc.nextInt();
		int c2=sc.nextInt();

		for(int i=0;i<n;i++) {
			resource[i]=sc.nextInt();
		}
		
		for(int i=0;i<n;i++) {
			Arrays.fill(G[i],M);
		}
		G[c1][c1]=0;
		r[c1]=resource[c1];
		num[c1]=1;
		
		for(int i=0;i<m;i++) {
			int v1=sc.nextInt();
			int v2=sc.nextInt();
			int weight=sc.nextInt();
			G[v1][v2]=weight;
			G[v2][v1]=weight;
		}

		dijkstra(c1);

		System.out.print(num[c2]+" "+r[c2]);

	}
	
	public static void dijkstra(int c1) {

		for(int i=0;i<n;i++) {
			
			int u=-1;
			int min=M;
			for(int j=0;j<n;j++) {
				if(v[j]==0&&G[c1][j]<min) {
					min=G[c1][j];
					u=j;
				}
			}
			
			v[u]=1;
			
			for(int j=0;j<n;j++) {
				if(v[j]==0) {
					if(G[c1][u]+G[u][j]<G[c1][j]) {
						G[c1][j]=G[c1][u]+G[u][j];
						r[j]=r[u]+resource[j];
						num[j]=num[u];
						
					}else if(G[c1][u]+G[u][j]==G[c1][j]) {
						r[j]=Math.max(r[j], r[u]+resource[j]);
						num[j]+=num[u];
					}
				}
			}
		}
	}
}

下面这道题添加了两个第二标尺:最短路径数量num、每条边的花费cost,并且要求求出从起点到终点的最短路径及最短路径长度

PAT A1030 Travel Plan (30分)

原文链接:PAT A1030 Travel Plan
A traveler’s map gives the distances between cities along the highways, together with the cost of each highway. Now you are supposed to write a program to help a traveler to decide the shortest path between his/her starting city and the destination. If such a shortest path is not unique, you are supposed to output the one with the minimum cost, which is guaranteed to be unique.

Input Specification:
Each input file contains one test case. Each case starts with a line containing 4 positive integers N, M, S, and D, where N (≤500) is the number of cities (and hence the cities are numbered from 0 to N−1); M is the number of highways; S and D are the starting and the destination cities, respectively. Then M lines follow, each provides the information of a highway, in the format:

City1 City2 Distance Cost

where the numbers are all integers no more than 500, and are separated by a space.

Output Specification:
For each test case, print in one line the cities along the shortest path from the starting point to the destination, followed by the total distance and the total cost of the path. The numbers must be separated by a space and there must be no extra space at the end of output.

Sample Input:
4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20

Sample Output:
0 2 3 3 40

下图为《算法笔记》386页,对此题的解析
在这里插入图片描述

import java.util.*;
public class PAT_A1030_TravelPlan {

	static int MAXV=510;
	static int M=99999;
	
	static int n;
	static int[][] G=new int[MAXV][MAXV];
	static int[] v=new int[MAXV];
	
	static int[][] cost=new int[MAXV][MAXV];
	static int[] c=new int[MAXV];
	static String[] path=new String[MAXV];
	
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		n=sc.nextInt();
		int m=sc.nextInt();
		int s=sc.nextInt();
		int d=sc.nextInt();
		
		for(int i=0;i<n;i++) {
			Arrays.fill(G[i], M);
			path[i]=s+"";
		}
		G[s][s]=0;
		Arrays.fill(c, M);
		c[s]=0;
		
		for(int i=0;i<m;i++) {
			int v1=sc.nextInt();
			int v2=sc.nextInt();
			int dis=sc.nextInt();
			int co=sc.nextInt();
			G[v1][v2]=G[v2][v1]=dis;
			cost[v1][v2]=cost[v2][v1]=co;
		}
		
		dijkstra(s);
		
		System.out.print(path[d]+" "+G[s][d]+" "+c[d]);

	}
	
	public static void dijkstra(int s) {
		for(int i=0;i<n;i++) {
			int u=-1;
			int min=M;
			for(int j=0;j<n;j++) {
				if(v[j]==0&&G[s][j]<min) {
					u=j;
					min=G[s][j];
				}
			}
			
			if(u==-1) return ;
			v[u]=1;
			
			for(int j=0;j<n;j++) {
				if(v[j]==0) {
					if(G[s][u]+G[u][j]<G[s][j]) {
						G[s][j]=G[s][u]+G[u][j];
						path[j]=path[u]+" "+j;
						c[j]=c[u]+cost[u][j];
					}else if(G[s][u]+G[u][j]==G[s][j]) {
						if(c[u]+cost[u][j]<c[j]) {
						path[j]=path[u]+" "+j;
						c[j]=c[u]+cost[u][j];
						
						}
					}
				}
			}		
		}
	}
}

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Dijkstra迪杰斯特拉算法是一种典型的最短路径算法,可以用于计算一个节点到其他节点的最短路径。它的主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止,使用的是广度优先搜索的思想。该算法通过不断更新起始点到其他节点的距离,选择当前距离最短的节点进行扩展,直到所有节点都被扩展完毕,找到起始点到其他节点的最短路径。Dijkstra算法在网络路由、地图导航等领域有广泛应用。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [C++实现Dijkstra(迪杰斯特拉)算法](https://download.csdn.net/download/weixin_38692122/12724830)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Dijkstra迪杰斯特拉算法](https://blog.csdn.net/qq_43461641/article/details/100632351)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [DijkstraAlgorithm(迪杰斯特拉算法)](https://blog.csdn.net/qq_45740348/article/details/113575420)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值