算法 — 印章

问题描述

  共有n种图案的印章,每种图案的出现概率相同。小A买了m张印章,求小A集齐n种印章的概率。

输入格式

  一行两个正整数n和m

输出格式

  一个实数P表示答案,保留4位小数。

样例输入

2 3

样例输出

0.7500

数据规模和约定

  1≤n,m≤20

资源限制

时间限制:1.0s 内存限制:256.0MB

解题思路:

        该题目中采用动态规划思想,即一个多阶段问题一般由初始状态开始。题意为从总共有的 n 种中抽取 m 种,求集齐 n 种牌的概率。定义一个二维数组 arr[m + 1][n + 1] ,为了使得抽取个数的下标从 1 开始,故将数组中下标为 0 的元素闲置不用,故数组一维长度定义为 m + 1 和 n + 1。定义变量 i 对行号进行遍历,变量 j 对列号进行遍历,当 i < j 时该位置代表的概率(抽取 i 次集齐 j 种)为 0 。若 j 值为 1,故表示的意思是共抽取的 i 次但是只集齐了 1 种,故此时的概率是(1/n)^{i} * n,这里乘以 n 的原因是集齐的这 1 种有 n 种选择。对于其余情况的概率计算:该位置的上一行、同列位置的基础上再抽取一次(i 加一),此时抽取到的是原集齐的 j 种中的一种(j 不变);第二种情况是该位置的上一行、上一列位置的基础上再抽取一次(j 加一),此时抽取到的是除了原集齐的 j 种之外的其他种牌(j 加一),这个时候的概率计算如代码中所示。该算法的Java实现如下:

import java.text.DecimalFormat;
import java.util.*;
public class Main{
	public static void main(String[] args){
		Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        double p = 1.0 / n;
        double[][] dp = new double[m + 1][n + 1];
        DecimalFormat df = new DecimalFormat("0.0000");
        for (int i = 1; i <= m; i++) {
			for (int j = 1; j <= n; j++) {
				if (i < j) {
					dp[i][j] = 0;
                } else if (j == 1) {
                    dp[i][j] = Math.pow(p, i - 1);
                } else {
                    dp[i][j] = dp[i - 1][j] * (j * p) + dp[i - 1][j - 1] * ((n - j + 1) * p);
                }
            }
        }
        System.out.println(df.format(dp[m][n]));
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值