数据结构和算法:火车进出站

内卷之源:

https://www.nowcoder.com/practice/97ba57c35e9f4749826dc3befaeae109?tpId=37&&tqId=21300&rp=1&ru=/ta/huawei&qru=/ta/huawei/question-ranking

题目描述:

 * 给定一个正整数N代表火车数量,0<N<10
 * 接下来输入火车入站的序列,一共N辆火车,每辆火车以数字1~9编号
 * 火车站进出口是同一个,因此停在火车站的列车,只有后进站的出站了,先进站的才能出站——FILO
 * 要求输出火车出站的所有方案,并按字典序排序输出 —— 指方案之间的顺序

 * 备注:(1)有多组测试用例,每组第一行输入一个正整数N,第二行输入火车入站的序列。
 *              (2)各出站方案按字典序排序,换行输出,组成各方案的编号以空格间隔。

测试用例:

InputOutput

3

1 2 3 //只是进站顺序

1 2 3  //1进、1出、2进、2出、3进、3出

1 3 2  //1进、1出、2进、3进、3出、2出

2 1 3  //1进、2进、2出、1出、3进、3出

2 3 1  //1进、2进、2出、3进、3出、1出

//3 1 2 是不可能存在的,因为其要求:1进、2进、3进、3出、1出、2出

3 2 1  //1进、2进、3进、3出、2出、1出

4

2 1 4 3

1 2 3 4  //2进、1进、1出、2出、4进、3进、3出、4出

1 2 4 3  //2进、1进、1出、2出、4进、4出、3进、3出

//1 3 2 4 是不可能存在的,因为其要求:2进、1进、1出、4进、3进、3出、2出、4出

1 3 4 2  //2进、1进、1出、4进、3进、3出、4出、2出

……(共14种)

7

6 1 5 3 2 7 4

1 2 3 4 7 5 6

1 2 3 5 4 7 6

1 2 3 5 6 4 7

1 2 3 5 6 7 4

1 2 3 5 7 4 6

……(共429种)

思路分析:

    仔细观察表格Output列各方案会发现,在前一辆进站后,下一辆只有两种选择:一是在前一辆出站前完成进站并出站;二是在前一辆出站后完成进站并出站,但此情景还必须考虑上一辆之前是否还有未出站的车辆。按照FILO后续车辆依次类推即可。

    表格Output列各序列中同一编号第一次出现代表进站,第二次出现代表出站。因此基于完整的进出站序列,按照重复编号第二次出现的位置依次读取,然后进行排序即可。

编程实现(C++):

/*
 ************************************************************
 * @author    SLF
 * @version	  V1.0.0
 * @date      28-Jun-2021
 ************************************************************
 */

#include <iostream>
#include <vector>
#include <set>
#include <string>

using namespace::std;

int main(void)
{
    int N = 0; //0<N<10
    int n = 0;
    
    char pre = 0; //上一辆
    char in[9] = { 0 }; //入站序列
    string str;
    vector<string> vct; //方案组合
    set<string> set_vct; //方案排序
    int i = 0, j = 0;
    int num = 0, p = 0; //num:累计的在上一辆之前入站且还未出站的车辆数
    int len = 0, len2 = 0;
    unsigned int pos = 0;

    scanf("%d", &N);
    /*** 生成所有方案 ***/
    for (i = 0; i < N; ++i)
    {//火车编号0~9,为了方便搜索、插值,转为字符串处理起来更方便(局限性:不适于编号大于9)
        scanf("%d", &n);
        in[i] = n + ('0' - 0);
        if (vct.empty())
        {//第一辆
            pre = in[i];
            str.append(2, pre);
            vct.push_back(str);
            continue;
        }

        //当前车辆进出站只能是:
        // (1)在上一辆出站前 ———— 最简单
        // (2)在上一辆出站后 ———— 还需考虑上一辆之前是否有入站且还未出站的车辆,如有,则当前车辆进出站必须是在那些车辆出站前或出站后
        for (num = 0, j = 0, len = vct.size(); j < len; ++j)
        {//cout << "size: " << vct.size() << endl;
            //用于生成新方案
            str = vct[j];
            len2 = vct[j].size();

            //上一辆的进出站编号存放位置总是连续的:进站在前,出站紧跟在后
            pos = vct[j].rfind(pre);

            //(1)在上一辆出站前
            vct[j].insert((vct[j].begin() + pos), 2, in[i]);
            //(2)在上一辆出站后
            for (p = 1 + pos; p <= len2; ++p, ++num) //如果(1 + pos) < len2,则上一辆之前还有入站且还未出站的车辆
            {
                vct.push_back(str); //新的方案
                vct[len + num].insert((vct[len + num].begin() + p), 2, in[i]);
            }
        }

        pre = in[i];
    }
    // cout << endl << "total: " << vct.size() << endl;

    /*** 先删各方案进站编号,然后再排序 ***/
    for (j = 0, len = vct.size(); j < len; ++j)
    {//cout << vct[j] << endl;
        for (i = 0; i < N; ++i)
        {
            // vct[j].replace(vct[j].find(in[i]), 1, " "); //不得行!!!
            vct[j].erase(vct[j].find(in[i]), 1); //删除第一次出现的编号(进站)
        }
    }

    /*** 利用有序容器自动排序,然后输出 ***/
    set_vct.insert(vct.cbegin(), vct.cend());
    for (auto& iter : set_vct)
    {
        for (i = 0; i < (N - 1); ++i)
        {
            cout << iter[i] << ' ';
        }
        cout << iter[i] << endl;
    }

    return 0;
}

编程实现(C):

//TODO...

  

郑重提示:①解题思路非最优,覆盖条件可能不全,仅供练习参考。

                  ②若有更佳思路或疑问,可在评论区留言相互讨论,不亦乐乎。

                  ③本文不允许转载,若认可本文,可点赞收藏关注。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一列货运列车共有 n 节车厢,每节车厢将停放在不同的车。假定 n 个车的编号分别 为 1~n,车厢的编号与它们的目的地相同。货运列车按照从第 n 至第 1 的次序经过这 些车。为了便于从列车上卸掉相应的车厢,必须重新排列车厢,使各车厢从前至后按编号 1~n 的次序排列。当所有的车厢按照这种次序排列时,在每个车只卸掉最后一节车厢 即可。可以在一个转轨里完成车厢的重排工作,在转轨中有一个入轨,一个出轨和k 个缓冲铁轨(位于入轨和出轨之间)。 图 3-1 给出了一个转轨, 其中有 k=3 个缓冲铁轨 H1,H2 和 H3。开始时,n节车厢的货车从入轨处进入转轨,车厢重排结束时各车厢按照编号1至编号n的次序从出轨处离开转轨。在图 3-1(a)中,n=9,车厢从后至前的初始次序为 5,8,1,7,4,2,9,6,3。图 3-1(b)给出按所要求的次序重新排列后的结果。 为了重排车厢,从前至后依次检查入轨上的所有车厢。如果正在检查的车厢就是下一个满足排列的要求的车厢,可以直接把它放到出轨上。如果不是,则把它移动到缓冲铁轨上, 直到按输出次序要求轮到它时才将它放到出轨上。由于缓冲铁轨上车厢的进和出都是在其顶 部进行的,因此缓冲铁轨是按照 LIFO 的方式使用的。在重排车厢过程中,仅允许以下移动:  车厢可以从入轨移动到一个缓冲铁轨的顶部或者出轨上;  车厢可以从一个缓冲铁轨的顶部移动到的出轨上;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值