卡特兰数 HDU2067 & HDU4165 & HDU1134 小兔的棋盘 Pills Game of Connections

题目链接:https://vjudge.net/problem/HDU-2067

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 11800    Accepted Submission(s): 5952

Problem Description
小兔的叔叔从外面旅游回来给她带来了一个礼物,小兔高兴地跑回自己的房间,拆开一看是一个棋盘,小兔有所失望。不过没过几天发现了棋盘的好玩之处。从起点(0,0)走到终点(n,n)的最短路径数是C(2n,n),现在小兔又想如果不穿越对角线(但可接触对角线上的格点),这样的路径数有多少?小兔想了很长时间都没想出来,现在想请你帮助小兔解决这个问题,对于你来说应该不难吧!
 
Input
每次输入一个数n(1<=n<=35),当n等于-1时结束输入。
 
Output
对于每个输入数据输出路径数,具体格式看Sample。
 
Sample Input
1 3 12 -1
 
Sample Output
1 1 2 2 3 10 3 12 416024
 
Author
Rabbit
 
Source
 
Recommend
lcy

题解:

卡特兰数的初步学习卡特兰数应用

2.卡特兰数计算公式:

 1) h(n) = h(0)*h(n-1) + h(1)*h(n-2) + ... + h(n-1)h(0) (n>=1) , 其中 h[0] = 1;

 2) h(n) = c(2n,n) - c(2n,n+1)(n=0,1,2,...) <==> h(n) = C(2n,n)/(n+1)

 3) h(n) = h(n-1)*(4*n-2) / (i+1)  ……此条计算公式容易溢出

注意:卡特兰数的计算很容易溢出。

代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <cmath>
 7 #include <queue>
 8 #include <stack>
 9 #include <map>
10 #include <string>
11 #include <set>
12 using namespace std;
13 typedef long long LL;
14 const int INF = 2e9;
15 const LL LNF = 9e18;
16 const int MOD = 1e9+7;
17 const int MAXN = 35+10;
18 
19 LL h[MAXN];
20 
21 void init()
22 {
23     memset(h, 0, sizeof(h));
24     h[0] = 1; h[1] = 1;
25     for(int i = 2; i<MAXN; i++)
26         for(int j = 0; j<i; j++)
27             h[i] += 1LL*h[j]*h[i-j-1];
28 }
29 
30 int main()
31 {
32     init();
33     int kase = 0, n;
34     while(scanf("%d", &n) && n!=-1)
35         printf("%d %d %lld
", ++kase, n, 2LL*h[n]);
36 }
View Code

题目链接: https://vjudge.net/problem/HDU-4165

Pills

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1626    Accepted Submission(s): 1139

Problem Description
Aunt Lizzie takes half a pill of a certain medicine every day. She starts with a bottle that contains N pills.

On the first day, she removes a random pill, breaks it in two halves, takes one half and puts the other half back into the bottle.

On subsequent days, she removes a random piece (which can be either a whole pill or half a pill) from the bottle. If it is half a pill, she takes it. If it is a whole pill, she takes one half and puts the other half back into the bottle.

In how many ways can she empty the bottle? We represent the sequence of pills removed from the bottle in the course of 2N days as a string, where the i-th character is W if a whole pill was chosen on the i-th day, and H if a half pill was chosen (0 <= i < 2N). How many different valid strings are there that empty the bottle?
 
Input
The input will contain data for at most 1000 problem instances. For each problem instance there will be one line of input: a positive integer N <= 30, the number of pills initially in the bottle. End of input will be indicated by 0.
 
Output
For each problem instance, the output will be a single number, displayed at the beginning of a new line. It will be the number of different ways the bottle can be emptied.
 
Sample Input
6 1 4 2 3 30 0
 
Sample Output
132 1 14 2 5 3814986502092304
 
Source
Recommend
lcy

题解:

有n片药,每天吃半片。当天要么在药罐中抽到把一片完整的药片,然后分成两半,吃一半,最后把另一半放回药罐中;要么抽到半片药片直接吃。问:有多少种情况? 单纯的卡特兰数。

代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <cmath>
 7 #include <queue>
 8 #include <stack>
 9 #include <map>
10 #include <string>
11 #include <set>
12 using namespace std;
13 typedef long long LL;
14 const int INF = 2e9;
15 const LL LNF = 9e18;
16 const int MOD = 1e9+7;
17 const int MAXN = 30+10;
18 
19 LL h[MAXN];
20 
21 void init()
22 {
23     memset(h, 0, sizeof(h));
24     h[0] = 1;
25     for(int i = 1; i<MAXN; i++)
26         for(int j = 0; j<i; j++)
27             h[i] += 1LL*h[j]*h[i-j-1];
28 }
29 
30 int main()
31 {
32     init();
33     int n;
34     while(scanf("%d", &n) && n)
35         printf("%lld
", h[n]);
36 }
View Code

题目链接:https://vjudge.net/problem/HDU-1134

Game of Connections

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5112    Accepted Submission(s): 2934

Problem Description
This is a small but ancient game. You are supposed to write down the numbers 1, 2, 3, ... , 2n - 1, 2n consecutively in clockwise order on the ground to form a circle, and then, to draw some straight line segments to connect them into number pairs. Every number must be connected to exactly one another. And, no two segments are allowed to intersect.

It's still a simple game, isn't it? But after you've written down the 2n numbers, can you tell me in how many different ways can you connect the numbers into pairs? Life is harder, right?
 
Input
Each line of the input file will be a single positive number n, except the last line, which is a number -1. You may assume that 1 <= n <= 100.
 
Output
For each n, print in a single line the number of ways to connect the 2n numbers into pairs.
 
Sample Input
2 3 -1
Sample Output
2 5
Source
 
Recommend
Eddy

题意:

1~2*n 顺时针排列成一圈, 用n条线段连接n对数,要求线段不能有交叉,问:有多少种连接情况?

题解:

可以将此题联想到出栈问题,这样就转化成卡特兰数了。

递推式一:

 1 import java.util.Scanner;
 2 import java.math.BigInteger;
 3 
 4 public class Main {
 5     
 6     public static void main(String[] args){
 7         
 8         BigInteger[] a = new BigInteger[105];
 9         
10         a[0] = BigInteger.ONE;
11         for(int i=1; i<=100; i++) {
12             a[i] = BigInteger.valueOf(0); 
13             for(int j=0;j<i;j++){
14                 a[i] = a[i].add(a[j].multiply(a[i-j-1]));
15             }
16         }
17             
18         Scanner input = new Scanner(System.in);
19         while(input.hasNext()){
20             int n=input.nextInt();
21             if(n==-1) break;
22             System.out.println(a[n]);
23         }
24     }
25 }
View Code

递推式二:

 1 import java.util.Scanner;
 2 import java.math.BigInteger;
 3 
 4 public class Main {
 5     
 6     public static void main(String[] args){
 7         
 8         BigInteger[] a = new BigInteger[105];
 9         
10         a[0] = BigInteger.ONE;
11         for(int i=1; i<=100; i++) {
12             a[i] = a[i-1].multiply(BigInteger.valueOf(4*i-2)).divide(BigInteger.valueOf(i+1));
13         }
14             
15         Scanner input = new Scanner(System.in);
16         while(input.hasNext()){
17             int n=input.nextInt();
18             if(n==-1) break;
19             System.out.println(a[n]);
20         }
21     }
22 }
View Code