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;
}
}
}