洛谷P1044 [NOIP2003 普及组] 栈

传送门→[NOIP2003 普及组] 栈 - 洛谷

方法一:递归

定义一个二维数组a[i][j],i表示队列剩余元素个数,j表示栈中元素个数;

当队列中元素为空:

此时只剩栈中元素,我们只能按照顺序依次push出栈,所以此时只有一种情况,返回一;

当队列中元素不为空:

①栈中元素为空,只能进行入栈操作(i-1,j+1)

②栈中元素不为空,可入栈(i-1,j+1),可出栈(i,j-1)

需要注意的是此题还用到记忆化搜索,否则你会收获TLE。

#include <cstdio>
#include <iostream>
using namespace std;
int n;
int a[20][20];//i表示队列剩余元素个数,j表示栈中元素个数;
int dfs(int i, int j) {
	if (a[i][j]) return a[i][j];//划重点:记忆化搜索,如果a[i][j]已经有值,就直接返回
	if (i == 0) return 1;//队列里没了,只剩栈了,只有一种情况,返回一
	if (j > 0) a[i][j] += dfs(i, j - 1);//如果栈里还有元素,可出栈
	a[i][j] += dfs(i - 1, j + 1);//不管栈里有没有,都可入栈
	return a[i][j];
}
int main()
{
	cin >> n;
	int ans=dfs(n, 0);
	cout << ans;
	return 0;
}

方法二:递推/DP

定义一个二维数组a[i][j],i表示总进栈数,j表示总出栈数;

那么,对于a[i][j],它的上一步操作是入栈或者出栈,若入栈(即上一步是a[i-1][j]),若出栈(即上一步是a[i][j-1])

a[i][j]=a[i-1][j]+a[i][j-1]

和递归同理,我们需要特别判断一下i和j相等的情况,此时栈内为空,上一步操作只能是出栈(即a[i][j-1])

那么边界在哪里呢,和上面的递归同理,当队列中元素为空时,这个时候,只剩栈中的元素啦,只能一个一个出栈啦,只有这一种方法。

好啦,上代码

#include <cstdio>
#include <iostream>
using namespace std;
int n;
int a[20][20];
int main()
{
	cin >> n;
	for (int i = 0; i <= n; i++) {
		a[i][0] = 1;//边界
	}
	for (int i = 1; i <= n; i++) {//i表示总进栈数,j表示总出栈数
		for (int j = 1; j <= i; j++) {//这里一定要注意j的范围,不要和我一样因为j的范围错了,得不出正确答案写了半天(我很菜我知道了)
			if (i == j) a[i][j] = a[i][j - 1];//此时栈内为空,上一步操作一定是出栈
			else a[i][j] = a[i][j - 1] + a[i - 1][j];//上一步是入栈或者出栈
		}
	}
	int ans = a[n][n];//当入栈数和出栈数都是n时,就可以输出辣
	cout << ans;
	return 0;
}

方法三:卡特兰数

卡塔兰数是什么,它可以吃吗

不会卡特兰数的看这里

【算法】震惊!!!史上最详细的卡特兰数浅谈!!!_Fighter的博客-CSDN博客_卡特兰数

还有这里算法中的数学---卡特兰数(解析+代码实现)_KI的博客-CSDN博客_c++卡特兰数

不管看哪里,学会就好啊哈哈

然后我们得到了一个式子  f[n]=f[0]∗f[n−1]+f[1]∗f[n−2]+...+f[n−1]∗f[0]

#include <cstdio>
#include <iostream>
using namespace std;
int a[20] = { 1,1 };
int n;
int main()
{
	cin >> n;
	for (int i = 2; i <= n; i++) {
		for (int j = 0; j < i; j++) {
			a[i] += a[i - j - 1] * a[j];
		}
	}
	cout << a[n];
	return 0;
}

  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值