问题描述:
- 给定一个随机函数f,等概率返回1~5中的一个数字,
这是唯一可以是使用的随机机制,如何实现等概率
返回1~7中的一个数字。- 给定一个随机函数f,等概率返回a~b中的一个字母,
这是唯一可以是使用的随机机制,如何实现等概率
返回a~d中的一个数字。
对于此类问题:二进制调整去拼。
给出一般的解法:
代码:
#include <iostream> // std::cout
#include <stdlib.h> // rand() srand() RAND_MAX(32767, 0x7fff)
/** 等概率返回a~b中的一个数
* 此函数封装好,只能用,不能修改。
* 假设 a < b
*/
inline int f(int a, int b) { // 7-14
return (rand() % (b - a + 1)) + a;
}
/** 用f等概率得到0和1
* a ~ b
*/
int rand01(int a, int b) {
int ans = 0;
bool isodd = (b - a) & 1 == 0;
int mid = (a + b) >> 1;
do {
ans = f(a, b);
} while (isodd && ans == mid);
return isodd ? (ans < mid ? 0 : 1): (ans <= mid ? 0 : 1);
}
/** 等概率返回 from ~ to
* 要求只能要f这个玩意儿。
* 假设限定 from < to
*/
int g(int from, int to) {
// 3 ~ 9
// 0 ~ 6
// 0 ~ range
int range = to - from;
int num = 1;
// 求0~range需要多少个2进制位
while ((1 << num) - 1 < range) {
num++;
}
// 最终的累加和,0位上+0还是1, 1位上+0还是1, 2位上加0还是1, ...
int ans = 0;
do {
ans = 0;
for (int i = 0; i < num; ++i) {
ans |= (rand01(7, 14) << i); // 这里假设给的f函数的区间为 7-14,同下面测试函数。
}
} while (ans > range);
return ans + from;
}
测试:
void test() {
// 7 - 14, 26 - 39
int from = 26, to = 39;
int ans[to - from + 1];
for (int i = 0; i < to - from + 1; ++i) {
ans[i] = 0;
}
int testTime = 10000000;
for (int i = 0; i < testTime; ++i) {
ans[g(from, to) - from]++;
}
for (int i = 0; i < to - from + 1; ++i) {
std::cout << from + i << "次数共有:" << ans[i] << "\n";
}
}
结果: 基本等概率返回。
问题描述:
给定一个随机函数f,以p概率返回0,以1-p概率返回1,这是你唯一可以使用的随机机制,如何实现等概率返回0和1。
这个题目大同小异,0和1组合有四种,返回0概率为p,返回1概率为1-p,(一般情况p!=0.5),那么怎么等概率返回0和1呢?
p*(1-p) == (1-p)*p
这点清楚了,问题不大了。
// 提供的这个函数不可见,只能使用
int f() {
return (rand() % 10) < 7 ? 0 : 1; // p为0.7
}
// 等概率返回0和1
int g() {
int first = 0;
do {
first = f();
} while (first == f());
return first;
}
纸上得来终觉浅,须知此事要躬行。