软件设计艺术大师基本功--掷色子n次求和为sum的概率

概率:掷筛子求和, 递归,分解成子问题是面试中经常考察的问题,多看看leetcode对面试者有好处。

有一个筛子,每投一次的结果可能是1,2,3,4,5,6,每种出现的结果相同。现在给定投掷的次数n,求n次
之和是sum的概率为多少。

解析

可以拆分成子问题,然后用递归的方式解决。
从最简单的开始分析:
n=1,sum=3,      则P(n,sum) = P(1,3)= 1/6;

n=2, sum =2, 则P(2,2)= 1/6 *1/6;可以将P(2,2)分解成P(1,1)* P(2-1,1);

n=3, sum =4, 可以分解为: P(1,1)*P(3-1,4-1) + P(1,2)*P(3-1,4-2) + P(1,3)*P(3-1,4-4),即将3次投递分解成第一次投递和剩余次数的投递,进而不断地分解,最后会分解到P(1,x);

从而一般地,P(n,sum) = P(1,x) + P(n-1,sum-x) ,其中x=1,2,3,4,5,6;
另外,计算P(n,sum)时,要判断一下是否满足,6n<=sum。

下面n>6的条件不应该加! 看后面的新代码。

#include <iostream>

using namespace std;

//n:总次数,sum:和
float cal(int n, int sum)
{
    if((n<1)||(n>6))
        return 0.0;
	
    if(sum > 6*n)
    {
        return 0.0;
    }
	
   //递归终止条件
    if( (n == 1) && (sum<=6) && (sum>=1) )
    {
        return 1/6.0;
    }

    float temp = 0.0;
	
    for(int a=1;a<=6;a++)//第一次投掷时可能出现1-6。
    {
        temp =temp +( cal(1,a) * cal(n-1,sum-a) );
    }
    return temp;
}

int main()
{
    cout << "Hello World!" << endl;
    float temp = -0.1;
    temp = cal(1,3);
    cout<<"Probability = "<<temp<<"  expected="<<1/6.0<<endl;
    temp = cal(2,12);
    cout<<"Probability = "<<temp<<"  expected="<<1/36.0<<endl;
    temp = cal(2,3);
    cout<<"Probability = "<<temp<<"  expected="<<2/36.0<<endl;

    temp = cal(3,3);
    cout<<"Probability = "<<temp<<"  expected="<<1/(6*6*6.0)<<endl;

    temp = cal(3,4);
    cout<<"Probability = "<<temp<<"  expected="<<3/(6*6*6.0)<<endl;


    getchar();
    return 0;
}

 

2020.10

#pragma once
#include <iostream>
//#include <>
class sumPosibility
{
public:
	sumPosibility();
	~sumPosibility();

	float solve(int times, int sum) {

		if (sum > 6 * times)
			return 0;
		if (sum < 1 * times)
			return 0;
		if (1 == times) {
			return 1 / 6.0f;
		}
		float resP = 0;
		
		//递推公式:  既分解成了子问题
		resP += solve(1, 1)*solve(times - 1, sum - 1);//第一次投出了1,剩余的times-1次需要和为sum-1
		resP += solve(1, 2)*solve(times - 1, sum - 2);//第一次投出了2,剩余的times-1次需要和为sum-2
		resP += solve(1, 3)*solve(times - 1, sum - 3);//第一次投出了2,剩余的times-1次需要和为sum-3
		resP += solve(1, 4)*solve(times - 1, sum - 4);//第一次投出了2,剩余的times-1次需要和为sum-4
		resP += solve(1, 5)*solve(times - 1, sum - 5);//第一次投出了2,剩余的times-1次需要和为sum-5
		resP += solve(1, 6)*solve(times - 1, sum - 6);//第一次投出了2,剩余的times-1次需要和为sum-6

		return resP;
	}

	float Test1() {

	}
	
};

int main() {
	sumPosibility obj;
	std::cout << obj.solve(1, 0) << "  expected=" << 0 << "  \n";
	std::cout << obj.solve(1, 1) << "  expected=" << 1/6.0f << "  \n";
	std::cout << obj.solve(1, 6) << "  expected=" << 1 / 6.0f << "  \n";

	std::cout << obj.solve(2, 3) << "  expected=" << 1 / 18.0f << "  \n";
	std::cout << obj.solve(3, 3) << "  expected=" << 1 / 1 / (6 * 6 * 6.0) << "  \n";
	std::cout << obj.solve(3, 4) << "  expected=" << 3 / 1 / (6 * 6 * 6.0) << "  \n";
	
	std::cout << obj.solve(7, 7) << "  expected=" << 1 / (6 * 6 * 6.0* 6 * 6 * 6.0*6.0) << "  \n";
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

First Snowflakes

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值