内卷之源:
题目描述:
* 给定一个正整数N代表火车数量,0<N<10
* 接下来输入火车入站的序列,一共N辆火车,每辆火车以数字1~9编号
* 火车站进出口是同一个,因此停在火车站的列车,只有后进站的出站了,先进站的才能出站——FILO
* 要求输出火车出站的所有方案,并按字典序排序输出 —— 指方案之间的顺序
* 备注:(1)有多组测试用例,每组第一行输入一个正整数N,第二行输入火车入站的序列。
* (2)各出站方案按字典序排序,换行输出,组成各方案的编号以空格间隔。
测试用例:
Input | Output |
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...
郑重提示:①解题思路非最优,覆盖条件可能不全,仅供练习参考。
②若有更佳思路或疑问,可在评论区留言相互讨论,不亦乐乎。
③本文不允许转载,若认可本文,可点赞收藏关注。