我遇到的问题如下:
写一个程序来发现这个谜题的答案:“让我们说男人和女人得到平等的报酬(来自同一个均匀分布)。如果女人随意约会并嫁给第一个薪水较高的男人,那么人口的比例是多少会结婚吗?“
我的问题是,我得到的结婚数字似乎是错误的。另一张海报asked this same question on the programmers exchange before和结婚百分比应该是~68%。但是,我接近75%(很多的差异)。如果有人可以看看,让我知道我哪里出错了,我将非常感激。
我意识到,在查看程序员交换的另一个问题时,这不是解决问题的最有效方法。但是,我想在使用更有效的方法之前以这种方式解决问题。
我的代码如下,大部分问题在测试函数中“已解决”:
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ARRAY_SIZE 100
#define MARRIED 1
#define SINGLE 0
#define MAX_SALARY 1000000
bool arrayContains(int* array, int val);
int test();
int main()
{
printf("Trial count: ");
int trials = GetInt();
int sum = 0;
for(int i = 0; i < trials; i++)
{
sum += test();
}
int average = (sum/trials) * 100;
printf("Approximately %d %% of the population will get married\n", average / ARRAY_SIZE);
}
int test()
{
srand(time(NULL));
int femArray[ARRAY_SIZE][2];
int maleArray[ARRAY_SIZE][2];
// load up random numbers
for (int i = 0; i < ARRAY_SIZE; i++)
{
femArray[i][0] = (rand() % MAX_SALARY);
femArray[i][1] = SINGLE;
maleArray[i][0] = (rand() % MAX_SALARY);
maleArray[i][1] = SINGLE;
}
srand(time(NULL));
int singleFemales = 0;
for (int k = 0; k < ARRAY_SIZE; k++)
{
int searches = 0; // count the unsuccessful matches
int checkedMates[ARRAY_SIZE] = {[0 ... ARRAY_SIZE - 1] = ARRAY_SIZE + 1};
while(true)
{
// ARRAY_SIZE - k is number of available people, subtract searches for people left
// checked all possible mates
if(((ARRAY_SIZE - k) - searches) == 0)
{
singleFemales++;
break;
}
int randMale = rand() % ARRAY_SIZE; // find a random male
while(arrayContains(checkedMates, randMale)) // ensure that the male was not checked earlier
{
randMale = rand() % ARRAY_SIZE;
}
checkedMates[searches] = randMale;
// male has a greater income and is single
if((femArray[k][0] < maleArray[randMale][0]) && (maleArray[randMale][1] == SINGLE))
{
femArray[k][1] = MARRIED;
maleArray[randMale][1] = MARRIED;
break;
}
else
{
searches++;
continue;
}
}
}
return ARRAY_SIZE - singleFemales;
}
bool arrayContains(int* array, int val)
{
for(int i = 0; i < ARRAY_SIZE; i++)
{
if (array[i] == val)
return true;
}
return false;
}
答案 0 :(得分:2)
首先,对于女性“随机约会”意味着什么,问题存在一些模糊之处。至少有两种似是而非的解释:
你绕过未婚女性,每个人随机抽取一个未婚男性,并根据工资决定是否结婚。在每次通过可用的女性时,这可能导致一些可用的男性被多个女性约会,而其他人则没有任何日期。
您将每个试验分成几轮。在每一轮中,你随机地将未婚男子洗牌给未婚女性,以便每个未婚男子与一位未婚女士约会。
在任何一种情况下,您都必须重复匹配,直到不再有可能的匹配为止,当符合条件的男性中的最高工资小于或等于符合条件的女性的最低工资时。
在我的测试中,这两种解释产生了略微不同的统计数据:约69.5%使用解释1结婚,约67.6%使用解释2. 100次潜在夫妇的100次试验足以在运行之间产生相当低的差异。例如,在该术语的共同(非统计)意义上,一组10次运行的结果在67.13%和68.27%之间变化。
然而,您似乎没有采取任何一种解释。如果我正确地阅读你的代码,你会完全一次通过这些女人,并且每个人都会随机抽取男人,直到你找到一个女人可以结婚或者你已经测试过每个人。应该清楚的是,这为女性早期的女性结婚带来了更大的机会,而基于顺序的偏见至少会增加结果的差异。我觉得它也有可能对更多的婚姻产生净偏见,但我没有一个好的支持论据。
此外,正如我在评论中所写,你通过选择随机整数的方式引入了一些偏见。对于rand()
个可能的值,int
函数会在0
和RAND_MAX
之间返回RAND_MAX + 1
个%
。为了论证,我们假设这些值均匀分布在该范围内。如果您使用N
运算符将结果的范围缩小到N
个可能的值,那么仅当RAND_MAX + 1
均分rand()
时,该结果仍然均匀分布,否则更多rand()
结果映射到某些值而不是映射到其他值。事实上,这适用于您可能想到的任何严格的数学变换,以缩小RAND_MAX
结果的范围。
对于工资,我不明白为什么你甚至懒得将它们映射到限制范围。 /*
* Returns a random `int` in the half-open interval [0, upper_bound).
* upper_bound must be positive, and should not exceed RAND_MAX + 1.
*/
int random_draw(int upper_bound) {
/* integer division truncates the remainder: */
int rand_bound = (RAND_MAX / upper_bound) * upper_bound;
for (;;) {
int r = rand();
if (r < rand_bound) {
return r % upper_bound;
}
}
}
与其他任何人一样,最高工资;从模拟中收集的统计数据不依赖于工资的范围;但只是在他们的统一分配上。
然而,为了在数组中选择随机索引,无论是绘图人还是改组,都需要一个有限的范围,所以你需要注意。在这种情况下减少偏差的最佳方法是强制绘制的随机数来自 的范围,可以通过重新绘制选项的数量将其平均分割,以确保它:
{{1}}