您的位置:首页 > 编程语言 > Java开发

hdu1023 Train Problem II 卡特兰数,JAVA大数类

2016-03-19 11:52 615 查看

Train Problem II

[b]Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 7578 Accepted Submission(s): 4081

[/b]

[align=left]Problem Description[/align]
As we all know the Train Problem I, the boss of the Ignatius Train Station want to know if all the trains come in strict-increasing order, how many orders that all the trains can get out of the railway.

[align=left]Input[/align]
The input contains several test cases. Each test cases consists of a number N(1<=N<=100). The input is terminated by the end of file.

[align=left]Output[/align]
For each test case, you should output how many ways that all the trains can get out of the railway.

[align=left]Sample Input[/align]

1
2
3
10


[align=left]Sample Output[/align]

1
2
5
16796

Hint
The result will be very large, so you may not process it by 32-bit integers.


出栈次序

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

常规分析

首先,我们设f(n)=序列个数为n的出栈序列种数。(我们假定,最后出栈的元素为k,显然,k取不同值时的情况是相互独立的,也就是求出每种k最后出栈的情况数后可用加法原则,由于k最后出栈,因此,在k入栈之前,比k小的值均出栈,此处情况有f(k-1)种,而之后比k大的值入栈,且都在k之前出栈,因此有f(n-k)种方式,由于比k小和比k大的值入栈出栈情况是相互独立的,此处可用乘法原则,f(n-k)*f(k-1)种,求和便是Catalan递归式。ps.author.陶百百)

首次出空之前第一个出栈的序数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。

令h(0)=1,h(1)=1,catalan数满足递推式[1] :

h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0) (n>=2)

例如:h(2)=h(0)*h(1)+h(1)*h(0)=1*1+1*1=2

h(3)=h(0)*h(2)+h(1)*h(1)+h(2)*h(0)=1*2+1*1+2*1=5

另类递推式[2] :

h(n)=h(n-1)*(4*n-2)/(n+1);

递推关系的解为:

h(n)=C(2n,n)/(n+1) (n=0,1,2,...)

递推关系的另类解为:

h(n)=c(2n,n)-c(2n,n-1)(n=0,1,2,...)

本来想用C++记忆化递推,结果结果没超时,long long爆了。。。。

到几十的时候long long就已经爆了。。。

WA代码......

#include <cstdio>
#include <iostream>
#include <cstring>

using namespace std;

long long Cata[120], N;

long long f(long long x) {
if (Cata[x]) return Cata[x];  //记忆化搜索
long long sum = 0;
for (long long i = 1; i <= x; i++) {
sum += (f(i - 1) * f(x - i));
}
return Cata[x] = sum;   //记忆化搜索
}

int main()
{
while (~scanf("%I64d", &N)) {
memset(Cata, 0, sizeof(Cata));
Cata[0] = Cata[1] = 1;
printf("%I64d\n", f(N));
}
return 0;
}


用java大数类做,用一个数组递推,慢就慢点吧,方便很多

import java.math.*;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
BigInteger[] c = new BigInteger[105];
c[0] = BigInteger.valueOf(1);
c[1] = BigInteger.valueOf(1);
for (int i = 2; i <= 100; i++) {
c[i] = c[i - 1].multiply(BigInteger.valueOf(4 * i - 2)).divide(BigInteger.valueOf(i + 1));
}
Scanner in = new Scanner(System.in);
int n;
while (in.hasNext()) {
n = in.nextInt();
System.out.println(c
);
}
in.close();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: