题目链接火车进站
这道题乍一看很可能会看成求数字的全排列,我就是犯了这个错误。其实这题求得是符合一定条件的全排列,也就是说题目要求的输出序列只是全排列的一部分。
那输出的序列需要满足哪些要求呢(=?=)
其实我们可以通过模拟得出结果,通过模拟火车进站、出站可以将整个过程分为三个状态,在这里记为A,B,C,A代表已经出站的火车(也就是已经排好序的序列),B代表此时正在站中的火车,C代表还未进站的火车。
可以发现,C中的数字一定是大于A或B中的数字的,假设我们已经放了k个数字,那么我们接下来只可以进行两种操作。
第一种操作是B出站,第二中操作C是入站,因为题目要求按字典序输入,也就是小->大,所以我们只需模拟这个过程的全部情况并且尽可能保证操作一在操作二之前(这句话的意思是:如果可以进行操作一,就进行操作一,如果不能进行操作一,就是此时站中没有元素,才进行操作二)即可。
可以用vector来表示A,stack表示B,int变量表示C;
c++代码如下:
#include<iostream>
#include<stack>
#include<vector>
using namespace std;
const int N=25;
vector<int>a;
stack<int>b;
int c=1,n,cnt=20;
void dfs(){
if(!cnt)return;
if(a.size()==n){
cnt--;
for(auto i:a)cout<<i;
cout<<endl;
return;
}
if(b.size()){
a.push_back(b.top());
b.pop();
dfs();
b.push(a.back());
a.pop_back();
}
if(c<=n){
b.push(c);
c++;
dfs();
c--;
b.pop();
}
}
int main(){
cin>>n;
dfs();
return 0;
}
-----------------------2021/4/17补充
今天在看一道题时学习了卡特兰数,才发现这个题其实就是求卡特兰数,只不过需要输出方案序列,所以需要用dfs,如果只是单纯的求方案数量,那就可以直接套公式了,卡特兰数一般有两种求法,一种是用费马小定理(这种方法需要满足mod与n互质),一种是扩展欧几里得算法(还没学)
卡特兰数公式如下:
C(n,2n)/n+1
费马小定理求逆元:
设kmi(a,b,mod)函数为求a的b次方对mod取余,则kmi(a,mod-2,mod)可以求逆元。