HDU 3625 Examining the Rooms

题目链接:

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


解题思路:

1.首先要知道Stirling数(斯特林数):

   第一类Stirling数:把n个可区分对象分成k个非空循环列(至少含一个数)的方法数,记为s(n,k)。

  1. 递推公式:s(n,k)=s(n-1,k-1)+(n-1)*s(n-1,k) (1<=k<=n-1)
  2. 其中:s(n,n)=1(n>=0),s(n,0)=0(n>=1) 【注意s(0,0)=1】
  3. 理解:考虑加入第n个时,有两种情况:
  4.     1)前n-1个构成了k-1个非空循环列,第n个单独构成一个循环列,有方法数s(n-1,k-1)种
  5.     2)前n-1个构成了k个非空循环列,第n个加入其中某个循环列的某个位置,共有(n-1)个位置可加入,有方法数(n-1)*s(n-1,k-1)种;         

   第二类Stirling数:把n个可区分对象分成k个非空集合的方法数,记为S(n,k)。

  1. 递推公式:S(n,k)=S(n-1,k-1)+k*S(n-1,k) (1<=k<=n-1)
  2. 其中:S(n,n)=1(n>=0),S(n,0)=0(n>=1)【注意S(0,0)=1】
  3. 理解:与第一类Stirling数相似,考虑加入第n个时,有两种情况:
  4.     1)前n-1个构成了k-1个非空集合,第n个单独构成一个集合,有方法数S(n-1,k-1)种;
  5.     2)前n-1个构成了k个非空集合,第n个加入其中某个集合,共有k个集合可加入,有方法数k*S(n-1,k-1)种;

第一类Stirling数与第二类Stirling数的区别:

  • 区别即在“非空循环列”与“集合”,非空循环列中的数有一定顺序,而集合没有,例如【1,2,3,4,5】与【1,3,2,5,4】,它们是两个非空循环列,但却是同一个集合。

第一类Stirling数举例:

  • 如本题。。

第二类Stirling数举例:

  • 如把编号为1-n的n个小球放入k个一模一样(无法区别)的盒子中,每个盒子中至少有一个,问有多少种方法。(根据递推公式写一个递归函数即可解决)

2.然后考虑到这道题,实际就属于第一类Stirling数。把这n个房间分成k个非空循环列,对于每一种分法,都有唯一的放钥匙的顺序使得每个非空循环列中的房间依次按其循环列中的排列顺序打开,比如若n=5,k=2,若把这5个房间分为2个非空循环【1,2】【3,4,5】,则唯一的放钥匙顺序为【2,1,4,5,3】(第一个数字2表示第一个房间放第二个房间的钥匙,以此类推),因此可以知道当n个房间被分为k及小于k个非空循环列时的相应钥匙放置方法可以打开所有房间,但是第一间房间不能撞破,所以第一间房间不能单独形成一个循环列,只能是让其余n-1个房间构成k个非空循环列后再加入其中某个循环列的某个位置,则综合以上,该题所有能最终打开所有房间的钥匙放置方法有(n-1)*s(n-1,k)+(n-1)*s(n-1,k-1)+...+(n-1)*s(n-1,1)种,而所有钥匙放置可能有n!种,所以最终的可能为两者相除。(尽我最大努力在说清楚了。。看不明白欢迎问。。)


总结:

数学要好好学啊。。


代码如下:

#include<cstdio>
__int64 stirling1(__int64 n,__int64 k)
{
	if (n==k)return 1;
	else if (n>0&&k==0)return 0;
	else return (n-1)*stirling1(n-1,k)+stirling1(n-1,k-1);
}
__int64 rank(__int64 a)
{
	for (__int64 i=a-1;i>1;i--)a*=i;
	return a;
}
int main()
{
	int T;
	scanf("%d",&T);
	while (T--)
	{
		int n,k;
		scanf("%d %d",&n,&k);
		__int64 y=0,z=rank(n);
		for (int i=1;i<=k;i++)y+=(n-1)*stirling1(n-1,i);
		printf("%.4f\n",(double)y/(double)z);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值