内容会持续更新,有错误的地方欢迎指正,谢谢!
题目
在一次活动中,我们需要按可控的比例来随机发放我们的奖品,假设需要随机的物品id和概率都在给定的Map<String,Double> prizeMap
中,请实现如下这个函数: String getRandomPrize(Map<String,Double>prizeMap){}
使得返回的结果为参与者即将得到的一个随机物品id.
prizeMap
中的数据为:
物品id 投放概率
1 0.5
2 0.3
3 0.1
4 0.95
5 0.05
分析
法1:直接从左到右一次相加。每次相加都记录相加后的结果:0.5 0.8 0.9 1.85 1.9,if(产生的随机数<=0.5)则说明选到了物品1,else if(产生的随机数<=0.8)则说明选到了物品2,以此类推。
法2:将0.5 0.3 0.1 0.95 0.05按照比例映射为[0,1]之间的数,再将映射后的五个数从左到右相加。剩余步骤同法1后半部分。
我用的法1
所用数据结构: map和string
代码
#include <iostream>
#include <string>
#include <map>//map由红黑树实现,其中的关键字有序
using namespace std;
string getRandomPrize(map<string,double> prizeMap)
{
double sum=0;
map<string,double>::iterator iter=prizeMap.begin();
map<string,double> tempMap;
while(iter!=prizeMap.end())
{
sum+=iter->second;
tempMap.insert(pair<string, double>(iter->first,sum));
++iter;
}
//计时器原理实现种子,若每次调用时都重新设置种子了,那么多次调用的结果都是相同的
//srand((unsigned)time(NULL));
//产生[a,b]上的随机数 ((double)rand()/RAND_MAX)*(b-a) + a ,其中
//(double)rand()/RAND_MAX)可以得到一个0~1的随机数
double total = (double(rand()) / RAND_MAX) * sum;//产生0到sum之间的浮点数
map<string,double>::iterator it=tempMap.begin();
while(it!=tempMap.end())
{
if(total<(*it).second)
return (*it).first;
++it;
}
}
int main()
{
map<string,double> prizeMap = {{"1",0.5},{"2",0.3},{"3",0.1},{"4",0.95},{"5",0.05}};
int i=5000;
srand((unsigned)time(NULL));//应该在这里设种子,这样每次调用结果才随机。
while(i--)
cout << getRandomPrize(prizeMap) << endl;
return 0;
}
验证正确性:把main()改成如下代码:
//添加了统计每个id出现的次数的功能
int main()
{
map<string,double> prizeMap = {{"1",0.5},{"2",0.3},{"3",0.1},{"4",0.95},{"5",0.05}};
int i=5000;
srand((unsigned)time(NULL));//应该在这里设种子,这样每次调用结果才随机。
string temp;
int count[6]={0};
while(i--)
{
temp=getRandomPrize(prizeMap);
cout<<temp<<endl;
count[atoi(temp.c_str())]++;
}
for(int i=1;i<=5;++i)
cout<<count[i]<<" : ";
return 0;
}
输出结果为:
1243 : 790 : 267 : 2567 : 133 约等于 0.5:0.3:0.1:0.95:0.05
结论:正确!