uva 10648 dp+计数


把n个巧克力放进m个盒子中,求至少有一个盒子为空的概率
直接求解情况比较多,可以考虑先求每个盒子都不空的概率

要求每个盒子至少有一个,可以先在每个盒子中放一个巧克力,在任意去放剩下的n-m个巧克力
由于巧克力是一样的,盒子也是一样的,所以可以考虑为将n-m个相同的巧克力分组,组数最多为m组
每一种分组对应一种放法,只要知道有多少不同的分组就行了
但这种做法我没有办法想出一个递推公式或是通项公式,网上也没找到,好像需要分类讨论

这里我们用动态规划来做

我们用dp[i][j]表示i个巧克力放进j个盒子使得每个盒子都不为空的概率
注意这里盒子可能并没有放满,我们考虑的是在这m个盒子中,我们用i个巧克力放满j个盒子的概率,和原问题不等价
当我们放第i个巧克力的时候,对于已经放好的巧克力有两种情况,1 i-1个巧克力已经使得j个盒子每个盒子都有一个巧克力,所以这时我们只需要往j个盒子中任意放一个巧克力即可,结果为dp[i-1][j]/j
2 i-1个巧克力使得j-1个盒子都有一个巧克力,所以我们需要在剩余的m-j-1个盒子中任意放一个巧克力即可,
结果为dp[i-1][j-1]/(m-j-1) 
综上 dp[i][j]=dp[i-1][j]/j+dp[i-1][j-1]/(m-j-1)

感想 计数问题有时会与dp问题相关联,但万变不离其宗,都需要找到一个递推公式

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<iomanip>
#include<string>
#include<stack>
#include<algorithm>
#pragma warning(disable:4996)
using namespace std;
int main()
{
	double dp[105][105], f[106];
	int i, j, k, n, m;
	k = 0;
	while (cin >> n) {
		if (n == -1) break;
		cin >> m;
		memset(dp, 0, sizeof(dp));
		for (i = 1; i <= m; i++) f[i] = (double)i / m;
		dp[1][1] = 1;
		for (i = 2; i <= n; i++)
			for (j = 1; j <= m; j++) {
				dp[i][j] = dp[i - 1][j] * f[j] + dp[i - 1][j - 1] * f[m - j + 1];
			}
		printf("Case %d: %.7f\n", ++k, 1 - dp[n][m]);
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值