csp ccf 2017年12月份第4/四题 java实现 90分

题目:

试题编号:201712-4
试题名称:行车路线
时间限制:1.0s
内存限制:256.0MB
问题描述:
问题描述
  小明和小芳出去乡村玩,小明负责开车,小芳来导航。
  小芳将可能的道路分为大道和小道。大道比较好走,每走1公里小明会增加1的疲劳度。小道不好走,如果连续走小道,小明的疲劳值会快速增加,连续走 s公里小明会增加 s 2的疲劳度。
  例如:有5个路口,1号路口到2号路口为小道,2号路口到3号路口为小道,3号路口到4号路口为大道,4号路口到5号路口为小道,相邻路口之间的距离都是2公里。如果小明从1号路口到5号路口,则总疲劳值为(2+2) 2+2+2 2=16+2+4=22。
  现在小芳拿到了地图,请帮助她规划一个开车的路线,使得按这个路线开车小明的疲劳度最小。
输入格式
  输入的第一行包含两个整数 nm,分别表示路口的数量和道路的数量。路口由1至 n编号,小明需要开车从1号路口到 n号路口。
  接下来 m行描述道路,每行包含四个整数 tabc,表示一条类型为 t,连接 ab两个路口,长度为 c公里的双向道路。其中 t为0表示大道, t为1表示小道。保证1号路口和 n号路口是连通的。
输出格式
  输出一个整数,表示最优路线下小明的疲劳度。
样例输入
6 7
1 1 2 3
1 2 3 2
0 1 3 30
0 3 4 20
0 4 5 30
1 3 5 6
1 5 6 1
样例输出
76
样例说明
  从1走小道到2,再走小道到3,疲劳度为5 2=25;然后从3走大道经过4到达5,疲劳度为20+30=50;最后从5走小道到6,疲劳度为1。总共为76。
数据规模和约定
  对于30%的评测用例,1 ≤  n ≤ 8,1 ≤  m ≤ 10;
  对于另外20%的评测用例,不存在小道;
  对于另外20%的评测用例,所有的小道不相交;
  对于所有评测用例,1 ≤  n ≤ 500,1 ≤  m ≤ 10 5,1 ≤  ab ≤  nt是0或1, c  ≤ 10 5。保证答案不超过10 6

考试时只得了60分,后来做了下得了80分:

思路:对于迪杰斯特拉算法进行修改,在保存从起点到各个终点的dist中(dist会被不断更新),一个终点对应一个key,而value不仅仅保存路径的值,还保存当前路径的最后一段路径的信息,如果该路段是连续的一段小道,将对后面产生影响,假设当前到终点B的需要更新,当前最短路径的到终点A已经选出来,需要从A出发到B构成新路径 ,起点-x-x-A-B,(x-x代表未知的一段)来试探是否新路径更短,如果此时A-B也是小道,而之前起点到A的最后一段路径也是连续的小道,设为(C-D-A),cd之间为L1,Da之间为L2,它们都是小道,A-B之间也是小道设为L3,连续的小道应该算上A-B,为(L1+L2+L3)的平方,我们已经知道(L1+L2)的平方(说明:这保存在之前说的数据结构中),(L1+L2+L3)的平方 = ((L1+L2)的开方+L3)的平方,这只是其中一种特殊的情况,通过这样不断的更新dist,最终求得答案


代码如下(可以直接提交):只得了80分,目前还不知道原因,不知道有没有100分的大佬讲讲其他思路

代码有很多优化的地方,只是为了验证正确性,所以没多去修改

更新:看了别人的博客说int类型会爆,于是修改了下,然后90分,其他地方没怎么修改

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.Set;

public class Main {
	public static void main(String[] args) throws Exception {
		Scanner scanner = new Scanner(System.in);
		int n = scanner.nextInt();
		int m = scanner.nextInt();
		Dij.Node[][] martix = new Dij.Node[n][n];
		for(int i= 0;i<m;i++) {
			int t = scanner.nextInt();
			int a = scanner.nextInt();
			int b = scanner.nextInt();
			int c = scanner.nextInt();
			martix[a-1][b-1] = new Dij.Node(c, t==0?true:false);
			martix[b-1][a-1] = new Dij.Node(c, t==0?true:false);
		}
		Dij dij = new Dij(martix, n);
		dij.dij(0);
		dij.output();
	}
}
/**
 * 核心算法实现类
 * @author colin
 */
class Dij {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
	private int vertexNum;//顶点数量
	private Node[][] martix;//邻接矩阵
	private boolean[] U;//候选集合点,还没有找到最短路径的点
	private Map<Integer,Path> dist = new HashMap<>();//保存最短路径key代表终点 value代表当前的最短路径
	private int currentMidVertex;//当前的中间点,也就是每次产生的最短路径的那个点,该点之前不再S集合中
	private int startVertex = 0;
	public Dij(Node[][] martix,int vertexNum) {
		this.martix = martix;
		this.vertexNum = vertexNum;
		U = new boolean[vertexNum];
	}
	private void init(int startVertex) {
		//初始化U集合和dist集合
		for(int i = 0; i<vertexNum; i++) {
			U[i] = true;
			if(i!=startVertex) {
				if(martix[startVertex][i]!=null) {
					Path path = new Path();
					if(!martix[startVertex][i].isWideRoad) {
						path.totalDistance = martix[startVertex][i].distance * martix[startVertex][i].distance;
						path.lastStagePath.distance = path.totalDistance;
						path.lastStagePath.isWideRoad = false;
					} else {
						path.totalDistance = martix[startVertex][i].distance;
						path.lastStagePath.distance = martix[startVertex][i].distance;
						path.lastStagePath.isWideRoad = true;
					}
					dist.put(i, path);
				} else {
					Path path = new Path();
					path.totalDistance = Long.MAX_VALUE;
					dist.put(i, path);
				}
			}
		}
		U[startVertex] = false;
		//初始化中间点
		this.currentMidVertex = startVertex;
	}
	public void dij(int startVertex) {//从哪个顶点出发
		this.startVertex = startVertex;
		init(startVertex);
		//顶点个数-1次循环,每次从U集合中取出一个点
		for(int i = 1;i<vertexNum;i++) {//循环顶点个数-1那么多次,每次加入一个顶点到S集合中
			currentMidVertex = shorestPath();//找到dist中当前最短路径的终点是哪一个
			if(currentMidVertex==Long.MAX_VALUE) {//如果出现v1-v2没有路径,那么从U集合中能拿出来的点都拿出来了
				continue;
			}
			U[currentMidVertex] = false;//从候选集合中拿出去
			//更新dist,使得其他路径经过currentMidVertex,如果路径值更小那么更新
			Set<Entry<Integer,Path>> set = dist.entrySet();
			for (Entry<Integer, Path> entry : set) {
				if(entry.getKey()!=currentMidVertex&&U[entry.getKey()]) {
					Path first = dist.get(currentMidVertex);
					//新的路径就等于比如:当前的最短路径的终点是v3,若起点是v1,终点是v6,那么新的路径就是要找到是否可以经过v3从v1到v6,而只需要检测是否v3可以达到v6,如果可以那么新的路径就为v1->XXX->v3->v6         
					Node second = path(currentMidVertex,entry.getKey());
					Path wait2update = entry.getValue();
					//第二段没路可走
					if(second==null) {
						continue;
					}
					//如果后一段是小路 
					long result = Long.MAX_VALUE;
					if(!second.isWideRoad) {
						//如果前一段路也是小路
						if(!first.lastStagePath.isWideRoad) {
							long a = first.lastStagePath.distance;
							//新构成的路径长度
							result = (int) (first.totalDistance +2* Math.sqrt(a)*second.distance+ second.distance * second.distance);
							if(result < wait2update.totalDistance) {
								wait2update.totalDistance = result;
								wait2update.lastStagePath.distance = (int) (a+2* Math.sqrt(a)*second.distance+ second.distance * second.distance);
								wait2update.lastStagePath.isWideRoad = false;
							}
						//前一段路是大路	
						} else {
							result = first.totalDistance+second.distance * second.distance;
							if(result < wait2update.totalDistance) {
								wait2update.totalDistance = result;
								wait2update.lastStagePath.distance = second.distance * second.distance;
								wait2update.lastStagePath.isWideRoad = false;
							}
						}
					//后一段路是大路
					} else {
						result  = first.totalDistance + second.distance;
						if(result < wait2update.totalDistance) {
							wait2update.totalDistance = result;
							wait2update.lastStagePath.distance = second.distance;
							wait2update.lastStagePath.isWideRoad = true;
						}
					}
				}
			}
		}
	}
	public void output() {
		System.out.println(dist.get(vertexNum-1).totalDistance);
	}
	private Node path(int start, Integer destination) {//寻找一个路径起点是start,终点是destination
		if(martix[start][destination]!=null) {
			return martix[start][destination];
		}
		return null;
	}
	//遍历dist返回当前的最短路径的终点是哪个
	public int shorestPath() {
		Set<Entry<Integer,Path>> set = dist.entrySet();
		int minKey = Integer.MAX_VALUE;
		long minPath = Long.MAX_VALUE;
		for (Entry<Integer, Path> entry : set) {
			if(U[entry.getKey()]) {
				int key = entry.getKey();
				long value = entry.getValue().totalDistance;
				if(value < minPath) {
					minPath = value;
					minKey = key;
				}
			}
		}
		return minKey;
	}
	/**
	 *邻接矩阵元素数据结构
	 */
	public static class Node{
		public long distance = Long.MAX_VALUE;//
		public boolean isWideRoad = true;
		public Node(int distance,boolean isWideRoad) {
			this.distance = distance;
			this.isWideRoad = isWideRoad;
		}
		public Node() {
		}
	}
	/**
	 *描述到某个终点的最短距离
	 *需要不断更新 
	 */
	public static class Path{
		public long totalDistance = Long.MAX_VALUE;//保存距离的总和
		public Node lastStagePath = new Node();//保存最新阶段的路径,需要区分是大路还是小路 
	}
}






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值