算法学习——dijkstra算法

dijkstra算法可求单源最短问题,解说可查看blog:https://blog.csdn.net/yalishadaa/article/details/55827681

在CCF中的交通规划一题中遇到,我用的做法是0分(但是我找不出来问题,虽然说用临界矩阵存数组会过大可能会导致内存溢出,但是不可能10分都没有,而且测试数据也过了),思想就是用dijkstra计算最短路径,并且在沿途中纪录下得到的远点与每个点的最短路径中的点与点之间的最短距离,最后加起来等于所求。

题目为:http://118.190.20.162/view.page?gpid=T44

我的做法:

package csp.csp20169;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;


public class ReTrafficPlan {
	
	int[] dist; // 保存v0到点i的距离
	
	int[][] arr; // 保存图
	
	boolean[] s; // true表示已求出最短路径的点,false为未球场
	
	int[] prev;// i的前驱节点,本题中不需要
	
	int v0;// 源点 
	
	int n;
	
	int[] costto; //连同该点所需要的代价
	
	
	
	
	public static void main(String[] args){
		new ReTrafficPlan().run();
	}
	
	
	public void run(){
		Scanner scanner = new Scanner(System.in);
		n = scanner.nextInt();
		int m = scanner.nextInt();
		arr = new int[n][n];
		s = new boolean[n];
		costto = new int[n];
		prev = new int[n];
		dist = new int[n];
		v0 = 0;
		
		for(int i = 0;i < n;i++){
			for(int j = 0;j < n;j++){
				arr[i][j] = Integer.MAX_VALUE;
				arr[j][i] = Integer.MAX_VALUE;
			}
		}
		
		for(int i = 0;i < m;i++){
			int a = scanner.nextInt()-1;
			int b = scanner.nextInt()-1;
			int cost = scanner.nextInt();
			arr[a][b] = cost;
			arr[b][a] = cost;
		}
		
		int res = 0;
		dijstra();
		for(int i = 0;i < n;i++){
//			System.out.print( " pre " + i + " " + prev[i] + " ");
//			if(i != v0)res += arr[prev[i]][i];
			res += costto[i];
		}
//		System.out.println(Arrays.toString(costto));
		System.out.print(res);
	}
	
	
	public void dijstra(){
		
		
		// 1.初始化所有数据
		for(int i = 0;i < n;i++){
			if(arr[v0][i] != 0){
				dist[i] = arr[v0][0];
				prev[i] = v0;
			}else {
				dist[i] = Integer.MAX_VALUE;
				prev[i] = -1;
			}
			costto[i] = Integer.MAX_VALUE;
		}
		s[v0] = true;
		dist[v0] = 0;
		costto[v0] = 0;
//		costto[v0] = 0;
		
		// 求解过程
		
		for(int i = 0;i < n;i++){
			int minDist = Integer.MAX_VALUE; 
			int u = v0;
			// 找到未求出最短路径的集合U中距离v0最近的点u			
			for(int j = 0;j < n;j++){
				if(!s[j] && dist[j] < minDist){
					minDist = dist[j];
					u = j;
				}
			}
			
			// 把u加进S集合中
			s[u] = true;
			dist[u] = minDist;
			
			// 以u为中间点,修改U中的点到v0的距离(若变得更短,则更新)
			
			for(int j = 0;j < n;j++){
				if(!s[j]){
					int newDis = dist[u] + arr[u][j];
					if(dist[j] > newDis){
						dist[j] = dist[u] + arr[u][j];
						prev[j] = u;
						costto[j] = arr[u][j];
				}
					if(newDis == dist[j]){
						costto[j] = Math.min(costto[j], arr[u][j]);
					}
			}
		}
		
	}

}
}

 

另一个系统认可的做法(100):

该做法也是用了dijstra方法,它用优先队列来存放未找到最短路径的点。

package csp.csp20169;

import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Scanner;


public class ReTrafficPlan3 {
	
	
	public class Node implements Comparable<Node>{
		// 源点到index的距离
		int index;
		int cost;
		
		public Node(int index,int cost){
			this.index = index;
			this.cost = cost;
		}

		@Override
		public int compareTo(Node o) {
			// TODO Auto-generated method stub
			return this.cost - o.cost;
		}
	}
	
	public class Edge{
		// 边的第二个点
		int second;
		int cost;
		
		public Edge(int second,int cost){
			this.second = second;
			this.cost = cost;
		}
	}
	
	PriorityQueue<Node> queue;
	
	LinkedList<Edge>[] list;
	
	int[] disv;
	
	boolean[] s; // true表示已求出最短路径的点,false为未球场
	
	int[] prev;// i的前驱节点
	
	int v0;// 源点 
	
	int n;
	
	int[] costto; //连同该点所需要的代价
	
	
	
	
	
	public static void main(String[] args){
		new ReTrafficPlan3().run();
	}
	
	
	public void run(){
		Scanner scanner = new Scanner(System.in);
		n = scanner.nextInt();
		int m = scanner.nextInt();
		s = new boolean[n];
		costto = new int[n];
		prev = new int[n];
		list = new LinkedList[n];
		queue = new PriorityQueue<>();
		v0 = 0;
		disv = new int[n];
		for(int i = 0;i < list.length;i++){
			list[i] = new LinkedList<>();
			disv[i] = Integer.MAX_VALUE;
			costto[i] = Integer.MAX_VALUE;
		}
	
		for(int i = 0;i < m;i++){
			int a = scanner.nextInt()-1;
			int b = scanner.nextInt()-1;
			int cost = scanner.nextInt();
			list[a].add(new Edge(b,cost));
			list[b].add(new Edge(a, cost));
		}
		disv[v0] = 0;
		costto[v0] = 0;
		int res = 0;
		queue.add(new Node(v0, 0));
		
		dijstra();
		for(int i = 1;i < n;i++){
			res += costto[i];
		}
//		System.out.println(Arrays.toString(costto));
		System.out.print(res);
	}
	
	
	public void dijstra(){
		
		while(!queue.isEmpty()){
			// 每次都得到未找到最短路径的离源点最近的点
		Node node = queue.poll();
		int curP = node.index;
		s[curP] = true;
		for(int i = 0;i < list[curP].size();i++){
			Edge edge = list[curP].get(i);
			int nextP = edge.second;
			if(!s[nextP]){
				int cost = edge.cost;

				// 若找到以curP为中间点,与源点连接的路径变短的点nextP,则更新dist[nextP]
						int newDis = cost + disv[curP];
						if(disv[nextP] > newDis){
							disv[nextP] = newDis;
							costto[nextP] = cost; 
							// 更新完把该点放进未找到最短路径的集合进行遍历,放在这里
//							queue.add(new Node(nextP, disv[nextP]));
						}
						if(newDis == disv[nextP]){
							costto[nextP] = Math.min(costto[nextP], cost);
						}
						// 若此条语句放在这里也可,但是会运行超时,因为有很多多余的节点要遍历
						queue.add(new Node(nextP, disv[nextP]));
			}
		}
	
		}
	}

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值