hdu 2067 卡特兰数打表(求解多边形,圆形等分割问题,括号匹配)(一直在更新。。。)

百度百科:https://baike.baidu.com/item/%E5%8D%A1%E7%89%B9%E5%85%B0%E6%95%B0/6125746?fr=aladdin

不错的网易博客:http://blog.163.com/lz_666888/blog/static/1147857262009914112922803/

卡特兰数又称卡塔兰数,英文名Catalan number,是组合数学中一个常出现在各种计数问题中出现的数列。

令h(1)=1,h(0)=1,catalan数满足递归式:

  h(n)= h(1)*h(n-1) + h(2)*h(n-2) + ... + h(n-1)h(1) (其中n>=2)
  另类递归式:
  h(n)=((4*n-2)/(n+1))*h(n-1);

  该递推关系的解为:
  h(n+1)=C(2n,n)/(n+1) (n=1,2,3,...)

其前几项为 : 1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440, 9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420, 24466267020, 91482563640, 343059613650, 1289904147324, 4861946401452, ...百科上有的写的很深,不好理解,随着看的博文多了,理解的会深一些 。

分割问题



自己推的代码如下,当时并不知道这是卡特兰数,比赛时用了一个小时左右硬生生的推出来的:


#include<stdio.h>

int main()
{
	int n;
	long long sum;
	long long dp[3005];
	dp[0]=1; dp[1]=1; dp[2]=2; dp[3]=5;
	for(int i=4;i<=3000;i++)
	{
		int tem=i;
		int cnt=tem/2;
		sum=0;
		for(int j=0;j<cnt;j++)
		{
			sum+=(dp[j]*dp[tem-1-j]*2)%100000007;
		}
		if(tem%2==1)
			sum+=(dp[cnt]*dp[cnt])%100000007;
		dp[i]+=sum%100000007;
	}
	while(~scanf("%d",&n))
		printf("%lld\n",dp[n]);
	return 0;
}

再看看比较官方的代码:

#include<stdio.h>
#define mod 100000007

int main()
{
	int n;
	long long sum;
	long long dp[3005];
	dp[0]=1; dp[1]=1;
	for(int i=2;i<=3002;i++)
	{
		dp[i]=0;
		for(int j=0;j<i;j++)
			dp[i]=(dp[i]+dp[j]*dp[i-j-1])%mod;
	}
	while(~scanf("%d",&n))
		printf("%lld\n",dp[n+1]);
	return 0;
}

官方代码Java大数版,在不要求取余的情况下用。

import java.math.BigInteger;
import java.util.Scanner;


public class Main {

	public static void main(String[] args) {
		int n;
		Scanner cin = new Scanner(System.in);
		BigInteger[] bb = new BigInteger[105];
		bb[0] = BigInteger.valueOf(1);
		bb[1] = BigInteger.valueOf(1);
		
		for (int i = 2; i <= 100; i++) {
			bb[i] = BigInteger.valueOf(0);
			for (int j = 0; j < i; j++)
				bb[i] = bb[i].add(bb[j].multiply(bb[i - j - 1]));
		}
		while (cin.hasNext()) {
			n = cin.nextInt();
			if (n == -1)
				break;
			System.out.println(bb[n]);
		}
	}
}


另类递归式:

  h(n)=((4*n-2)/(n+1))*h(n-1); 在计算时就算是double 类型精度也不够,只能算前30个数,所以我用了java高精度,这里以hdu 2067为例。

代码如下:

import java.math.BigDecimal;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner cin=new Scanner(System.in);
		BigDecimal [] BB = new BigDecimal [40];
		int inde=0;
		BB[0]=BigDecimal.valueOf(1);
		BB[1]=BigDecimal.valueOf(1);
		for(int i=2;i<=36;i++)
		{
			BB[i]=BigDecimal.valueOf(4*i-2).multiply(BB[i-1]);
			BB[i]=BB[i].divide(BigDecimal.valueOf(i+1));
		}
		int n;
		while(cin.hasNext())
		{
			n=cin.nextInt();
			if(n==-1)
				break;
			System.out.printf("%d %d ",++inde,n);
			System.out.println(BB[n].multiply(BigDecimal.valueOf(2)));
		}
		cin.close();
	}
}

括号匹配问题:

对于n对括号,合法的排列共有C(n,2n) - C(n+1,2n)种.

分析:n对括号,n个左括号,n个右括号;这里可以假设有2n个空,随机选出n空,填入左括号,剩下的由右括号填充。

以两对括号为例 :


先把红色的放上。剩下的是填充的,这样前一半的递推式就解决了。

然后,分析这里面应该剔除的 C(n+1,2n) 种,这里这个方法十分的巧妙;首先假设左括号为1,右括号为-1,从左到右依次加起来,如果这个这个序列不合格的,必然存在一个k使得1~k的和为-1;将1~k这k个括号反转(转化一下,求解),则这n对括号会分为n+1个左括号,n-1个有括号;

综上所述,这样的序列一共C(n+1,2n)种,都是不合法的。

所以C(n,2n) - C(n+1,2n),得证。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值