题意
给出一个正整数N,给出abc,…(n)个字母,依次出栈,进栈,有多少种序列。
输入:N
输出:第一行输出出栈序列个数,接下来每行输出一个序列
分析
深搜,模拟进栈,出栈过程。
void dfs(int index, int n, int l, int o, stack<char> in, queue<char> out)
index:第几次过程,从0开始
n:n个字母
l:进栈个数 初始0
o:出栈个数 初始0
in:进栈的元素
out:出栈的元素
当进栈个数l大于出栈个数o才能出栈,当进栈个数小于n才能进栈.
当index = n * 2时停止,输出out中的元素。
每次进出栈的过程,栈中元素和出栈元素初始都在参数中。所以当遇到既能出栈又能进栈的过程时,需要将放在后面函数还原回初始过程的参数。代码对应段中有解释。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[30][30] = {0};
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
ll cal(ll n, ll m) {
if (m == 0 || m == n)
return 1;
if (a[n][m] != 0)
return a[n][m];
a[n][m] = cal(n - 1, m) + cal(n - 1, m - 1);
return a[n][m];
}
bool book[20];
void dfs(int index, int n, int l, int o, stack<char> in, queue<char> out) {
if (index == 2 * n) {
while (!out.empty()) {
cout << out.front();
out.pop();
}
cout << endl;
return ;
}
if (l > o) { // 出栈
// 若将出栈函数放进栈函数下面,会导致回溯时,如果当前参数既可以出栈又可以进栈的话,
// 会先执行进栈函数,进栈函数会将参数的in加入元素,只需要判断是否可以
// 执行上面的入栈函数,若执行则还原参数的in
// if (l < n)
// in.pop();
out.push(in.top());
in.pop();
dfs(index + 1, n, l, o + 1, in, out);
}
if (l < n) { // 进栈
// 若将出栈函数放进栈函数下面,会导致回溯时,如果当前参数既可以出栈又可以进栈的话,
// 会先执行出栈函数,出栈会将参数的进栈in退出栈顶元素,只需要判断是否可以
// 执行上面的出栈函数,若执行则还原参数的in栈
if (l > o) {
in.push(out.front());
out.pop();
}
in.push('a' + l);
dfs(index + 1, n, l + 1, o, in, out);
}
}
int main(int argc, char** argv) {
int n;
cin >> n;
stack<char> in;
queue<char> out;
cout << cal(2 * n, n) / (n + 1) << endl;
dfs(0, n, 0, 0, in, out);
return 0;
}