【栈,Catalan】NOIP2003 普及组 栈

60 篇文章 0 订阅

这道题其实等价于下面这个题目:

1 1 ~N N N 个自然数和一个无限大的栈,没个书都要进栈并出栈一次,如果进栈的顺序为1,2,3,4,...,N2,N1,N,那么可能的出栈序列有多少种

方法一 搜索(枚举/递推), O(2N) O ( 2 N )

一个很直观的想法是,面对任何一种状态我们只有两种选择

1.把下一个数进栈

2.把当前栈顶的数出栈(如果栈非空)

用递归实现这个程序,时间复杂度为 O(2N) O ( 2 N ) ,这样就得到了所有可能的出栈序列方案。

方法二 递推 O(N2) O ( N 2 )

SN S N 表示进栈顺序为 1,2,...,N 1 , 2 , . . . , N 时可能的出栈序列综述

划分子问题后可以划分成 k1 k − 1 个数进出栈和 Nk N − k 个数进出栈这两个子问题,得到递推公式

SN=k=1NSk1×SNk S N = ∑ k = 1 N S k − 1 × S N − k

方法三 动态规划 O(N2) O ( N 2 )

F[i][j] F [ i ] [ j ] 表示有 i i 个数尚未进栈,目前有j个数在栈里,剩下的数都已出栈时的方案总数

在最终状态下,所有数都已出栈,得到边界 F[0][0]=1 F [ 0 ] [ 0 ] = 1

最终目标是所有数尚未进栈时可以得到上述边界的总数,所以目标为 F[N][0] F [ N ] [ 0 ]

每一步的两种决策分别是入栈和出栈,所以得到方程:

F[i][j]=F[i1][j+1]+f[i][j1] F [ i ] [ j ] = F [ i − 1 ] [ j + 1 ] + f [ i ] [ j − 1 ]

方法四 数学 O(N) O ( N ) ~ O( O ( 能过 ) )

该问题等价与求第N Catalan C a t a l a n 数,即 CN2N/(N+1) C 2 N N / ( N + 1 ) (当然, Catalan C a t a l a n 数的求法不止这一个,其他题解中都有写到,这里就不详细提及了)

对于 C(x,y) C ( x , y ) 的求法,有以下主要的两种

1. C(x,y)=x!/y!/(xy)! C ( x , y ) = x ! / y ! / ( x − y ) !

2. C(x,y)=C(x1,y1)+C(x1,y) C ( x , y ) = C ( x − 1 , y − 1 ) + C ( x − 1 , y )

注意,第一种求法可能会爆出范围最好是直接用第二种。

代码 阶乘求Catalan 60分

#include<cstdio>
using namespace std;int n;
unsigned long long jc[101];
long long c(int x,int y)
{
    return jc[x]/jc[y]/jc[x-y];//通式
}
int main()
{
    scanf("%d",&n);
    jc[0]=1;//0的阶乘就是1
    for(int i=1;i<101;i++) jc[i]=jc[i-1]*i;//计算
    printf("%lld",c(n<<1,n)/(n+1));//输出
}

Ac代码

#include<cstdio>
using namespace std;int n;
long long C[41][41];
long long c(int x,int y)//杨辉金字塔求法
{
    if(x==y||!y) return 1;
    if(y==1) return x;
    if(C[x][y]) return C[x][y];
    return C[x][y]=c(x-1,y)+c(x-1,y-1);
}
int main()
{
    scanf("%d",&n);
    printf("%lld",c(n<<1,n)/(n+1));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值