Atcoder ABC342 E - Last Train

Last Train(最后一班火车)

时间限制:2s 内存限制:1024MB

【原题地址】

所有图片源自Atcoder,题目译文源自脚本Atcoder Better!

点击此处跳转至原题

【问题描述】

在这里插入图片描述

【输入格式】

在这里插入图片描述
在这里插入图片描述

【输出格式】

在这里插入图片描述

【样例1】

【样例输入1】

6 7
10 5 10 3 1 3
13 5 10 2 3 4
15 5 10 7 4 6
3 10 2 4 2 5
7 10 2 3 5 6
5 3 18 2 2 3
6 3 20 4 2 1

【样例输出1】

55
56
58
60
17

【样例说明1】

在这里插入图片描述

【样例2】

【样例输入2】

5 5
1000000000 1000000000 1000000000 1000000000 1 5
5 9 2 6 2 3
10 4 1 6 2 3
1 1 1 1 3 5
3 1 4 1 5 1

【样例输出2】

1000000000000000000
Unreachable
1
Unreachable

【样例说明2】

在这里插入图片描述

【样例3】

【样例输入3】

16 20
4018 9698 2850 3026 8 11
2310 7571 7732 1862 13 14
2440 2121 20 1849 11 16
2560 5115 190 3655 5 16
1936 6664 39 8822 4 16
7597 8325 20 7576 12 5
5396 1088 540 7765 15 1
3226 88 6988 2504 13 5
1838 7490 63 4098 8 3
1456 5042 4 2815 14 7
3762 6803 5054 6994 10 9
9526 6001 61 8025 7 8
5176 6747 107 3403 1 5
2014 5533 2031 8127 8 11
8102 5878 58 9548 9 10
3788 174 3088 5950 3 13
7778 5389 100 9003 10 15
556 9425 9458 109 3 11
5725 7937 10 3282 2 9
6951 7211 8590 1994 15 12

【样例输出3】

720358
77158
540926
255168
969295
Unreachable
369586
466218
343148
541289
42739
165772
618082
16582
591828

【解题思路】

老汉使用到的是DP+优先队列优化的解题方式

本题是求每个站点到N站点的最晚出发时间。
利用站点关系从N站点开始递推回去,最晚出发时间值存在与该站点最晚一班车发车时间和下一站点到N站点最晚发车时间减去该站点到下一站点的途中用时c之间的最小值,利用优先队列取大根,减少没必要的计算,优化时间复杂度,最后判断该站到N站点最晚出发时间是否被赋值,是则输出该值,否则输出"Unreachable"

代码注释有详细过程

【代码】

package ABC342_E_LastTrain;

import java.io.*;
import java.util.*;

public class Main {
	static Vector<Node>[] g;

	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
	static StreamTokenizer st = new StreamTokenizer(br);

	public static int readInt() throws IOException {
		st.nextToken();
		return (int) st.nval;
	}

	public static void main(String[] args) throws IOException {
		int n = readInt();
		int m = readInt();
		// 用于存放对应的上一站点到达当前点的数据
		g = new Vector[n + 1];
		for (int i = 0; i < n + 1; i++) {
			g[i] = new Vector<>();
		}
		// 存入对应站点数据
		for (int i = 0; i < m; i++) {
			int l = readInt();
			int d = readInt();
			int k = readInt();
			int c = readInt();
			int A = readInt();
			int B = readInt();
			g[B].add(new Node(A, l, d, k, c));
		}
		// 存放从下标位置站点出发到N站点的最晚出发时间
		long[] dp = new long[n + 1];
		// 默认值为-1
		Arrays.fill(dp, -1);
		// 创建优先队列,创建为大根堆,以出发到达N站点的出发时间为比较值
		PriorityQueue<Pair> que = new PriorityQueue<>(new Comparator<Pair>() {
			@Override
			public int compare(Pair o1, Pair o2) {
				if (o1.val > o2.val)
					return -1;
				else if (o1.val < o2.val)
					return 1;
				return 0;
			}
		});
		// dp起始点为N站点
		que.add(new Pair((long) 4e18, n));
		while (!que.isEmpty()) {
			Pair cur = que.poll();
			// 如果当前dp值已经赋值,跳过,由于优先队列排序,第一次赋值已经是最大值(最晚出发时间)
			if (dp[cur.x] != -1)
				continue;
			// 为当前dp值赋值
			dp[cur.x] = cur.val;
			// 遍历上一站点,求上一站点出发到N站点的最晚出发时间
			for (int i = 0; i < g[cur.x].size(); i++) {
				Node a = g[cur.x].get(i);
				// 该站点到N点的最晚出发时间减去上一站点到该站点的c值,求出上一站点允许的最晚出发时间
				long ms = cur.val - a.c;
				// 当这个最晚出发时间在上一站点的出发时刻表中时,求出符合上一站点的最晚出发时间
				if (ms >= a.l) {
					ms = Math.min((ms - a.l) / a.d, (a.k - 1)) * a.d + a.l;
					que.add(new Pair(ms, a.A));
				}

			}
		}
		// 如果dp未赋值,则说明无法到达N站点,有则输出该dp值
		for (int i = 1; i < n; i++) {
			if (dp[i] == -1)
				pw.println("Unreachable");
			else
				pw.println(dp[i]);
		}
		pw.flush();
		pw.close();
		br.close();
	}

	// 存放x站点到N站点所需时间
	public static class Pair {
		long val;
		int x;

		public Pair(long val, int x) {
			this.val = val;
			this.x = x;
		}

	}

	// 存放到上一站点对应数据
	public static class Node {
		int A;
		long l;
		long d;
		long k;
		long c;

		public Node(int A, long l, long d, long k, long c) {
			this.A = A;
			this.l = l;
			this.d = d;
			this.k = k;
			this.c = c;
		}
	}

}

  • 17
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王老汉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值