招行信用卡中心2019秋招笔试题——抽取随机数字

题目:

游戏规则:给定三个因素N,K,W。游戏开始的时候有0点,如果发现自己手上的点数不足K点,则随机从1到W的整数中抽取一个,抽到每个整数的概率相同。重复上述步骤,直到手里的点数大于或等于K点。求这时候手上的点数小于等于N的概率。

例:

输入:N = 2,K = 2,W = 5

输出:0.24

说明:开始有0点,不足K(=2)点,于是从[1, 5]中抽取,抽到1或2才可以小于等于N(=2),抽到1和2的概率都是1/5。如果抽到1,则需要再抽一次,且必须抽到1才能小于等于N。因此,结果为1/5 + 1/5*1/5 = 0.24

题目思路:

以N = 21,K = 17,W = 10为例。

我们需要把最后一次抽取和之前的抽取分开考虑。既然最后一次总点数大于等于17,那么最后一次之前可能已经抽取了16,15, ..., 直到7(=17-10)。

(一)最后一次之前

那么最后一次之前已经抽取16的概率是多少呢?这里次数没有限定,可以是:

  • 第一次抽取了1(概率1/10),后面几次总共抽取15
  • 第一次抽取了2(概率1/10),后面几次总共抽取14
  • ...

因此可以用递归的方式来求这个概率。

这里我们可以事先定义一个数组,把已经得到的概率保存下来,这样递归调用的总次数就减少了。

(二)最后一次

再来看最后一次抽取。

  • 如果之前点数是7,那么最后一次只可以抽取10(才能大于等于17),总概率1/10
  • 如果之前点数是8,那么最后一次可以抽取9, 10,总概率2/10
  • ...
  • 如果之前点数是11,那么最后一次可以抽取6, 7, 8, 9, 10,总概率5/10
  • 如果之前点数是12,那么最后一次可以抽取5, 6, 7, 8, 9(才能不大于21),总概率5/10
  • ...

所以,这里只要根据N, K, W的大小搞清楚可以抽取哪几点就可以了。 

(三)整和在一起

最终概率是:P[之前总共抽取了7] * P[最后一次抽取10] + P[之前总共抽取了8] * P[最后一次抽取9或10] + ...

代码实现:

#include 
#include 
#include 
using namespace std;

int N;
int K;
int W;
vector probVec;			// 最后一次之前总共抽取点数的概率

double prob(int total);

int main()
{
	while (1)
	{
		cin >> N >> K >> W;

		if (N < K || N > K + W - 1)
		{
			cout << 0.0 << endl;
			continue;
		}

        // 初始化probVec
		probVec.clear();
		probVec.push_back(1);            // 抽取0的概率设置为1
		for (int i = 1; i < K; i++)
			probVec.push_back(-1);

		double ret = 0;
		for (int i = K - 1; i >= K - W && i >= 0; i--)  // 最后一次之前已经抽取i点
		{
			double reti = 1;
			int low = K - i;				        // 最后一次最低可以抽取多少
			int high = (i + W > N ? N - i : W);		// 最后一次最高可以抽取多少
			reti *= (high - low + 1.0) / W;			// 最后一次对应的概率
			reti *= prob(i);				        // 最后一次之前对应的概率
			ret += reti;
		}

		cout << fixed << setprecision(5) << ret << endl;
	}
	return 0;
}

//
// 计算最后一次之前总共抽取total点的概率
//
double prob(int total)
{
	if (probVec[total] != -1)            // 已经计算好,直接返回即可
		return probVec[total];

	double ret = 0;
	for (int i = 1; i <= W && total - i >= 0; i++)		// 第一次抽取i点
	{
		double reti = 1;			
		reti *= 1.0 / W;				// 选择i的概率
		reti *= prob(total - i);		// 选择(total-i)的概率
		ret += reti;
	}
	probVec[total] = ret;                // 记录在probVec里
	return ret;
}

 

你可能感兴趣的:(算法,C++)