1 条题解
-
0
题解思路
这是一道巧妙的双端队列模拟问题,需要理解火车站的运作机制和约束条件。
1. 问题建模分析
关键理解:
- 火车按编号1,2,...,n的顺序进站
- 车站可以看作一个双端队列,新火车从左端进入
- 出站口1(原进站口)对应从左端出站
- 出站口2(直行轨道)对应从右端出站
- 只有位于队列两端的火车才能出站
约束条件:
- 火车必须严格按1,2,...,n的顺序进站
- 每次出站的火车必须位于队列的左端或右端
- 需要验证给定出站序列是否可行
2. 双端队列模拟算法
核心思想:
- 使用双端队列维护当前站内的火车
- 对于出站序列中的每辆火车,尝试让其到达队列两端
- 如果无法到达任一端,则序列不可行
- 优先选择从左端(出站口1)出站,以最大化答案
算法流程:
-
初始化空的双端队列和next_in=1(下一个进站的火车编号)
-
对于出站序列中的每个火车need:
- 循环进站操作:如果need不在队列两端且还有火车未进站,则让下一辆火车进站
- 尝试出站:如果need在左端,从左端出站并计数;如果need在右端,从右端出站
- 如果need无法到达两端,返回-1
3. 贪心策略证明
为什么优先选择左端出站是最优的?
因为我们要最大化从出站口1出站的火车数量,所以当火车既可以从左端出站也可以从右端出站时,应该优先选择左端。这样的贪心选择不会影响后续的可行性,因为:
- 从左端出站的火车不会阻挡其他火车的出站路径
- 从右端出站的火车可能会阻挡后续火车从右端出站
4. 复杂度分析
-
时间复杂度:$O(n)$
- 每辆火车最多进站一次,出站一次
- 双端队列的操作均为$O(1)$
-
空间复杂度:$O(n)$(双端队列存储)
Java题解代码
import java.io.*; import java.util.*; public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int n = Integer.parseInt(br.readLine().trim()); String[] tokens = br.readLine().trim().split("\\s+"); int[] sequence = new int[n]; for (int i = 0; i < n; i++) { sequence[i] = Integer.parseInt(tokens[i]); } int result = maxTrainsFromExit1(n, sequence); System.out.println(result); } private static int maxTrainsFromExit1(int n, int[] sequence) { Deque<Integer> station = new LinkedList<>(); // 双端队列模拟车站 int nextTrainToEnter = 1; // 下一个要进站的火车编号 int exit1Count = 0; // 从出站口1出站的火车数量 for (int targetTrain : sequence) { // 让目标火车到达队列的某一端 while ((station.isEmpty() || (station.peekFirst() != targetTrain && station.peekLast() != targetTrain)) && nextTrainToEnter <= n) { // 新火车从左端进站 station.addFirst(nextTrainToEnter); nextTrainToEnter++; } // 尝试让目标火车出站 if (!station.isEmpty() && station.peekFirst() == targetTrain) { // 从左端(出站口1)出站 station.removeFirst(); exit1Count++; } else if (!station.isEmpty() && station.peekLast() == targetTrain) { // 从右端(出站口2)出站 station.removeLast(); } else { // 目标火车无法到达任一端,序列不可行 return -1; } } return exit1Count; } }
C++题解代码
#include <iostream> #include <deque> #include <vector> #include <ios> using namespace std; class TrainStationSolver { public: int maxTrainsFromExit1(int n, const vector<int>& sequence) { deque<int> station; // 双端队列模拟车站 int nextTrainToEnter = 1; // 下一个进站的火车编号 int exit1Count = 0; // 从出站口1出站的计数 for (int targetTrain : sequence) { // 循环进站直到目标火车到达队列两端之一 while ((station.empty() || (station.front() != targetTrain && station.back() != targetTrain)) && nextTrainToEnter <= n) { station.push_front(nextTrainToEnter); // 新火车从左端进站 nextTrainToEnter++; } // 尝试出站操作 if (!station.empty() && station.front() == targetTrain) { // 从左端(出站口1)出站,优先选择 station.pop_front(); exit1Count++; } else if (!station.empty() && station.back() == targetTrain) { // 从右端(出站口2)出站 station.pop_back(); } else { // 无法让目标火车到达两端,序列不合法 return -1; } } return exit1Count; } void solve() { ios_base::sync_with_stdio(false); cin.tie(nullptr); int n; cin >> n; vector<int> sequence(n); for (int i = 0; i < n; i++) { cin >> sequence[i]; } int result = maxTrainsFromExit1(n, sequence); cout << result << "\n"; } }; int main() { TrainStationSolver solver; solver.solve(); return 0; }
- 1
信息
- ID
- 303
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 5
- 标签
- 递交数
- 2
- 已通过
- 2
- 上传者