一、题目描述
开启了升降梯的动力之后,探险队员们进入了升降梯运行的那条竖直的隧道,映入眼帘的是一条直通塔顶的轨道、一辆停在轨道底部的电梯、和电梯内一杆控制电梯升降的巨大手柄。
Nescafé 之塔一共有 N 层,升降梯在每层都有一个停靠点。
手柄有 M 个控制槽,第 i 个控制槽旁边标着一个数Ci,满足C1<C2<C3<…<CM。
如果 Ci>0,表示手柄扳动到该槽时,电梯将上升 Ci 层;如果 Ci<0,表示手柄扳动到该槽时,电梯将下降 −Ci 层;并且一定存在一个 Ci=0,手柄最初就位于此槽中。
注意升降梯只能在 1~N 层间移动,因此扳动到使升降梯移动到 1 层以下、N 层以上的控制槽是不允许的。
电梯每移动一层,需要花费 2 秒钟时间,而手柄从一个控制槽扳到相邻的槽,需要花费 1 秒钟时间。
探险队员现在在 1 层,并且想尽快到达 N 层,他们想知道从 1 层到 N 层至少需要多长时间?
输入格式
第一行两个正整数 N、M。
第二行 M 个整数C1、C2…CM。
输出格式
输出一个整数表示答案,即至少需要多长时间。
若不可能到达输出-1。
数据范围
1≤N≤1000,
2≤M≤20,
−N<C1<C2<…<CM<N
输入样例:
6 3
-1 0 2
输出样例:
19
样例解释
手柄从第二个槽扳到第三个槽(0 扳到2),用时1 秒,电梯上升到3 层,用时4 秒。
手柄在第三个槽不动,电梯再上升到5 层,用时4 秒。
手柄扳动到第一个槽(2 扳到-1),用时2 秒,电梯下降到4 层,用时2 秒。
手柄扳动到第三个槽(-1 扳倒2),用时2 秒,电梯上升到6 层,用时4 秒。
总用时为(1+4)+4+(2+2)+(2+4)=19 秒。
二、题解
方法一:考建图
第一眼像是的 dp 啊,是的 dp 可以做,一个比较新颖的思路就是把问题转化为图论最短路问题:
- 结点 1 为源点,n 为终点。
- 原义为将电梯将移动 层,而在本算法中我将其表示为有向边的边权。
- 每个控制槽 代表不同的有向边,每一层电梯则为图中一个个的结点。
- 由于边权可能为负,因此可能存在无穷循环移动的情况。
- 至此,本问题可简化为求从 1 号点到 n 号点的最少时间花费。
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
static int n, m;
static int[] C;
static int[][] dist;
static int INF = 0x3f3f3f3f;
static void spfa(int S) {
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
dist[i][j] = INF;
}
Queue<Node> q = new ArrayDeque<>();
boolean[][] inq = new boolean[n+1][m+1];
q.add(new Node(1, S));
inq[1][S] = true;
dist[1][S] = 0;
while (!q.isEmpty()) {
Node t = q.poll();
int f = t.f, s = t.s;
inq[f][s] = false;
for (int i = 1; i <= m; i++) {
int tf = f + C[i];
if (tf < 1 || tf > n)
continue;
if (dist[tf][i] > dist[f][s] + Math.abs(f-tf)*2 + Math.abs(s-i)) {
dist[tf][i] = dist[f][s] + Math.abs(f-tf)*2 + Math.abs(s-i);
if (!inq[tf][i]) {
q.add(new Node(tf, i));
inq[tf][i] = true;
}
}
}
}
}
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
BufferedWriter w = new BufferedWriter(new OutputStreamWriter(System.out));
n = sc.nextInt();
m = sc.nextInt();
C = new int[m+1];
int start = 0;
for (int i = 1; i <= m; i++) {
C[i] = sc.nextInt();
if (C[i] == 0)
start = i;
}
int min = INF;
dist = new int[n+1][m+1];
spfa(start);
for (int i = 1; i <= m; i++) {
min = Math.min(min, dist[n][i]);
}
System.out.println(min == INF ? -1 : min);
}
static class Node {
int f, s;
Node(int f, int s) {
this.f = f;
this.s = s;
}
}
}
复杂度分析
- 时间复杂度: ,
- 空间复杂度: ,
方法二:dp
代办…
复杂度分析
- 时间复杂度: ,
- 空间复杂度: ,