您的位置:首页 > 其它

1133-Buy the Ticket

2013-09-11 23:09 232 查看

关于卡特兰数,网上多有博客,讲得也略感详细,可我为人较钻,也写写我的心得和体会,我历时三天,方才写出此题,首先从了解递推,了解了些dp,最后努力理解各公式的推导,最后根据栈出,栈入思考出了这道题。这类问题,没有比百度百科等更详细和专业的了,正因为它专业,倒是让我吃了一番苦头,在这里,我仍然借用百度百科来分析。希望大家耐心的看下去。

说道递推,其实我们高中就学习过,这里我以最简单的递推来让大家知道递推是什么,小明上有十个台阶的楼梯,一次能上一个台阶或二个台阶,问,小明上十阶台阶有几种上法,这是典型的fibonacci数列,fibonacci公式是f(n) = f(n-1) + f(n-2)。假设小明已经上到第十阶台阶了,那么他可能是由第八阶或第九阶来的,同理,第九阶时,有可能是由第八阶和第七阶上来的,逐一递推下去,就能得出结果,而动态规划在于记录状态(关于dp,我了解也不深),这里的每一阶台阶便是一个状态,此状态下记录有几种上楼梯的方法,根据加法原理,上楼总数为各步骤的总和,故有f(n)
= f(n-1) + f(n-2),n为第n阶楼梯,f(n)指有几种算法。

(百度百科)出栈次数:

一个(无穷大)的进栈序列为1,2,3,…,n,有多少个不同的出栈序列?[4-5]







常规分析

首先,我们设f(n)=序列个数为n的出栈序列种数。同时,我们假定,从开始到栈第一次出到空为止,这段过程中第一个出栈的序数是k。特别地,如果栈直到整个过程结束时才空,则k=n

首次出空之前第一个出栈的序数k将1~n的序列分成两个序列,其中一个是1~k-1,序列个数为k-1,另外一个是k+1~n,序列个数是n-k。

此时,我们若把k视为确定一个序数,那么根据乘法原理,f(n)的问题就等价于——序列个数为k-1的出栈序列种数乘以序列个数为n - k的出栈序列种数,即选择k这个序数的f(n)=f(k-1)×f(n-k)。而k可以选1到n,所以再根据加法原理,将k取不同值的序列种数相加,得到的总序列种数为:f(n)=f(0)f(n-1)+f(1)f(n-2)+……+f(n-1)f(0)。

看到此处,再看看卡特兰数的递推式,答案不言而喻,即为f(n)=h(n)= C(2n,n)/(n+1)= c(2n,n)-c(2n,n+1)(n=0,1,2,……)。

最后,令f(0)=1,f(1)=1。

下面是解买票问题的关键

非常规分析

对于每一个数来说,必须进栈一次、出栈一次。我们把进栈设为状态‘1’,出栈设为状态‘0’。n个数的所有状态对应n个1和n个0组成的2n位二进制数由于等待入栈的操作数按照1‥n的顺序排列(买票中没特定顺序哦)、入栈的操作数b大于等于出栈的操作数a(a≤b),因此输出序列的总数目=由左而右扫描由n个1和n个0组成的2n位二进制数,1的累计数不小于0的累计数的方案种数。

在2n位二进制数中填入n个1的方案数为c(2n,n),不填1的其余n位自动填0。从中减去不符合要求(由左而右扫描,0的累计数大于1的累计数)的方案数即为所求。

不符合要求的数的特征是由左而右扫描时,必然在某一奇数位2m+1位上首先出现m+1个0的累计数和m个1的累计数,此后的2(n-m)-1位上有n-m个 1和n-m-1个0。如若把后面这2(n-m)-1位上的0和1互换,使之成为n-m个0和n-m-1个1,结果得1个由n+1个0和n-1个1组成的2n位数,即一个不合要求的数对应于一个由n+1个0和n-1个1组成的排列。

反过来,任何一个由n+1个0和n-1个1组成的2n位二进制数,由于0的个数多2个,2n为偶数,故必在某一个奇数位上出现0的累计数超过1的累计数。同样在后面部分0和1互换,使之成为由n个0和n个1组成的2n位数,即n+1个0和n-1个1组成的2n位数必对应一个不符合要求的数。

因而不合要求的2n位数与n+1个0,n-1个1组成的排列一一对应。

显然,不符合要求的方案数为c(2n,n+1)。由此得出输出序列的总数目=c(2n,n)-c(2n,n+1)=c(2n,n)/(n+1)=h(n+1)。
如果你耐不下性子看上述言语,那你就放弃治疗吧,如果你看懂了上述,那么稍微提醒,你便能解决问题了,因为推导方法完全一样!!!

类似问题 买票找零

有2n个人排成一行进入剧场。入场费5元。其中只有n个人有一张5元钞票,另外n人只有10元钞票,剧院无其它钞票,问有多少中方法使得只要有10元的人买票,售票处就有5元的钞票找零?(将持5元者到达视作将5元入栈,持10元者到达视作使栈中某5元出)

提醒:当m < n时,输出为0.

#include<stdio.h>
#include<string.h>
int shu[500];
int big_mul(int b,int a[500],int size)
{
int jw = 0,t,i;
for(i = 0; i < size; i++)
{
t = a[i] * 	b + jw;
a[i] = t % 10;
jw = t / 10;
}
while(jw)
{
a[i++] = jw % 10;
jw /= 10;
size ++;
}
return size;
}
int main()
{

int m,n,text = 0;
while(scanf("%d%d",&m,&n)!= EOF && (m || n))
{

int size = 1;
memset(shu,0,sizeof(shu));
if(m < n)
{
printf("Test #%d:\n",++text);
printf("0");
}
else
{
if(!n)
{
shu[0] = 1;
for(int i = 2; i <= m; i++)
size = big_mul(i,shu,size);
}
else
{
shu[0] = 1;
for(int i = 2; i <= m + n;i ++)
{
if(i == (m+1)) size = big_mul(m-n+1,shu,size);
else size = big_mul(i,shu,size);
}
}
printf("Test #%d:\n",++text);
for(int i = size - 1;i >= 0;i--) printf("%d",shu[i]);
}
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: