hdoj/hdu 2512 一卡通大冒险 ( 集合划分问题 Bell 数)

本文详细介绍了如何计算贝尔数及其与Stirling数的关系,提供了具体的代码实现。

超级传送门:

http://acm.hdu.edu.cn/showproblem.php?pid=2512

 

题目大意:

 如{A,B,C}可以划分{{A},{B},{C}},  {{A,B},{C}},  {{B,C},{A}}, 
{{A,C},{B}},{{A,B,C}}。即一个集合可以划分为不同集合(1…n个)

给出一个数X,求出不同集合的种数。(结果%1000)

 

题目分析:

  n元集合分划为 k 类的方案数记为 S(n,k),称为第二类 Stirling 数。

每个贝尔数都是"第二类Stirling数"的和。   B(n) = Sum(1,n) S(n,k).

题目就是要求这个B(n),所以我们要求出Stirling 数,(参考资料http://zhidao.baidu.com/question/87414823.html

关于详细的解说,我学习了http://read.pudn.com/downloads65/sourcecode/math/232574/stir--%BC%AF%BA%CF%BB%AE%B7%D6%CE%CA%CC%E2/1/stir.ppt这个PPT

 

然后上面的分析给出了这种数的公式,下面代码实现就容易了:

注意:Bell数这个东西很大,第18个就已经超出了int了,幸好题目要求我们给出的答案%1000,不然要用大数做了

#include<iostream>
using namespace std;

const int N = 2001; 
int data[N][N], B[N]; 

void NGetM(int m, int n)// m 个数 n个集合  
{// data[i][j]:i 个数分成 j个集合  
	int  min, i, j; 
	data[0][0] = 1; //  
	for( i = 1; i <= m; ++i ) data[i][0] = 0; 
	for( i = 0; i <= m; ++i ) data[i][i+1] = 0; 
	for( i = 1; i <= m; ++i ){ 
		if( i < n ) min = i; 
		else min = n; 
		for( j = 1; j <= min; ++j ){ 
			data[i][j] = (j*data[i-1][j] + data[i-1][j-1])%1000;
		} 
	} 
} 
void compute(int m){// b[i]:Bell 数 
	NGetM(m, m); 
	memset(B, 0, sizeof(B)); 
	int i, j; 
	for( i=1; i <= m; ++i ) 
		for( j=0; j <= i; ++j ) B[i] += data[i][j]; 
} 

int main()
{
	int n,x;
	while(scanf("%d",&n) != EOF)
	{
		while(n--)
		{
			scanf("%d",&x);
			compute(x);
			printf("%d\n",B[x]%1000);
		}
	}
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值