车厢重排问题-java

一、问题引入

一列挂有 节车厢(编号从 1 到 )的货运列车途径 个车站,计划在行车途中将各节车厢停放在不同的车站。假设 个车站的编号从 1 到 ,货运列车按照从第 站到第 1 站的顺序经过这些车站,且将与车站编号相同的车厢卸下。
货运列车的各节车厢以随机顺序入轨,为方便列车在各个车站卸掉相应的车厢,须重排这些车厢,使得各车厢从前往后依次编号为 1 到 ,这样在每个车站只需卸掉当前最后一节车厢即可。
车厢重排可通过转轨站完成。一个转轨站包含一个入轨,一个出轨和 个位于入轨和出轨之间的缓冲轨。缓冲轨用于存储尚未确定输出次序的车厢。重排车厢的规则包含如下三条:

  1. 一个车厢从入轨移至出轨或缓冲轨;
  2. 一个车厢只有在其编号恰是下一个待输出编号时,可移到出轨;
  3. 一个车厢移到某个缓冲轨,仅当其编号大于该缓冲轨中队尾车厢的编号,若多个缓冲轨满足这一条件,则选择队尾车厢编号最大的,否则选择一个空缓冲轨,若无空缓冲轨则无法重排。
    请你编写程序实现这个重排算法。

输入格式:
输入在第一行中给出两个正整数n和k,均不超过 100,分别为车厢数量和缓冲轨数量。第二行按入轨顺序给出n节车厢的编号,数字间以空格分隔。

输出格式:
按照车厢进入出轨的顺序,输出每节车厢在入轨时的位序(从 0 开始),每个数字占一行。若无法重排,则在一行中输出信息

错误:任务不可能完成。

输入样例 1:

9 3
5 8 1 7 4 2 9 6 3

输出样例 1:

2
5
8
4
0
7
3
1
6

在这里插入图片描述

输入样例 2:

9 2
5 8 1 7 4 2 9 6 3

输出样例 2:

错误:任务不可能完成。

二、解决思路

在这里插入图片描述

算法步骤

  1. 初始化:创建k个缓冲轨(可以用栈或双端队列表示)
  2. 处理每节车厢:
    ◦ 如果当前车厢是下一个需要的编号,直接输出
    ◦ 否则,尝试将车厢放入合适的缓冲轨
  3. 检查缓冲轨:每次直接输出车厢后,检查缓冲轨顶部是否有下一个需要的车厢
  4. 处理剩余车厢:所有入轨车厢处理完后,检查缓冲轨中剩余的车厢是否能按顺序输出

关键点

• 缓冲轨选择策略:当需要将车厢放入缓冲轨时,优先选择队尾编号最大的缓冲轨,这样可以保持缓冲轨的降序排列,为后续车厢提供更多选择空间
• 及时检查缓冲轨:每次输出车厢后立即检查缓冲轨,确保不会错过可以输出的车厢

三、代码实现

import java.util.*;

public class Main {
    public static String canRearrange(int n, int k, List<Integer> carriages) {
        // 初始化缓冲轨
        List<Deque<Integer>> buffers = new ArrayList<>();
        for (int i = 0; i < k; i++) {
            buffers.add(new ArrayDeque<>());
        }

        int nextCarriage = 1; // 下一个待输出的车厢编号
        List<Integer> output = new ArrayList<>(); // 记录车厢进入出轨的顺序

        for (int i = 0; i < carriages.size(); i++) {
            int carriage = carriages.get(i);

            // 如果当前车厢是下一个待输出的车厢,直接输出
            if (carriage == nextCarriage) {
                output.add(i);
                nextCarriage++;
                // 检查缓冲轨中是否有可以输出的车厢
                while (true) {
                    boolean moved = false;
                    for (Deque<Integer> buffer : buffers) {
                        if (!buffer.isEmpty() && buffer.peekFirst() == nextCarriage) {
                            output.add(carriages.indexOf(buffer.pollFirst()));
                            nextCarriage++;
                            moved = true;
                        }
                    }
                    if (!moved) {
                        break;
                    }
                }
            } else {
                // 尝试将车厢放入缓冲轨
                int validBuffer = -1;
                int maxTail = -1;
                for (int j = 0; j < buffers.size(); j++) {
                    Deque<Integer> buffer = buffers.get(j);
                    if (buffer.isEmpty() || buffer.peekLast() < carriage) {
                        if (!buffer.isEmpty() && buffer.peekLast() > maxTail) {
                            validBuffer = j;
                            maxTail = buffer.peekLast();
                        } else if (buffer.isEmpty() && validBuffer == -1) {
                            validBuffer = j;
                        }
                    }
                }
                if (validBuffer != -1) {
                    buffers.get(validBuffer).addLast(carriage);
                } else {
                    return "错误:任务不可能完成。";
                }
            }
        }

        // 处理缓冲轨中剩余的车厢
        while (nextCarriage <= n) {
            boolean moved = false;
            for (Deque<Integer> buffer : buffers) {
                if (!buffer.isEmpty() && buffer.peekFirst() == nextCarriage) {
                    output.add(carriages.indexOf(buffer.pollFirst()));
                    nextCarriage++;
                    moved = true;
                }
            }
            if (!moved) {
                return "错误:任务不可能完成。";
            }
        }

        // 将输出顺序转换为字符串
        StringBuilder result = new StringBuilder();
        for (int idx : output) {
            result.append(idx).append("\n");
        }
        return result.toString().trim();
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 读取输入
        int n = scanner.nextInt();
        int k = scanner.nextInt();
        List<Integer> carriages = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            carriages.add(scanner.nextInt());
        }

        // 调用函数并输出结果
        String result = canRearrange(n, k, carriages);
        System.out.println(result);

        scanner.close();
    }
}

四、总结

车厢重排问题是一个经典的栈排序应用场景,考察对缓冲轨(栈结构)的灵活运用能力。该问题的核心在于如何利用有限的缓冲轨资源,将随机入轨的车厢重新排列成有序序列。通过分析,我们得出以下关键要点:
首先,算法采用贪心策略处理缓冲轨选择,优先将车厢放入队尾编号最大的缓冲轨。这种策略能最大化保留后续车厢的放置选择空间,是解决问题的关键所在。当车厢编号恰好是下一个待输出编号时,立即输出并触发缓冲轨的连锁检查机制,确保不会错过任何可输出的车厢。
其次,算法的时间复杂度为O(n²),因为每个车厢可能需要遍历所有缓冲轨进行放置或检查。空间复杂度为O(n),由缓冲轨的存储需求决定。值得注意的是,缓冲轨数量k直接影响问题可解性,当k不足时(如样例2中k=2无法处理峰值需求),算法会及时终止并返回错误信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值