我最近写了一个关于疯子等待飞机问题的程序,其中说:
100名航空公司的乘客正在等候登机。他们每人都持有该航班上100个座位中的一个的票。 (为方便起见,假设第n位乘客有一张座位号为n的票。) 不幸的是,第一个排队的人是疯了,并且会忽略他们机票上的座位号,随机挑选座位占据。所有其他乘客都很正常,除非已经被占用,否则他们会去正确的座位。如果它被占用,他们将随机找到一个免费座位。 登上飞机的最后一个(第100个)坐在合适座位(#100)的概率是多少?
我做了monte carlo以获得答案,但效率不高,因为乘客的座位位于座位上。我首先得到一个随机数,然后从第一个座位检查,如果它是选址,然后跳过那个。
顺便说一下答案应该是1/2:)
任何人都有更好的想法来做这个吗?
#include <iostream>
#include <vector>
#include <random>
using namespace std;
mt19937 generator;
uniform_real_distribution<double> ranuni(0, 1);
bool test(){
vector<int> line(100, 0);
int remaining(100);
int temp = remaining * ranuni(generator);
if (temp == 99)
return 0;
line[temp] = 1;
--remaining;
for (int i = 1; i < 99; ++i){
temp = remaining * ranuni(generator);
auto itr = line.begin();
while (temp != 0){
++itr;
if (*itr == 0)
--temp;
}
if (itr == line.end()-1)
return 0;
else
*itr = 1;
--remaining;
}
return 1;
}
int main(){
cout << "please input number of simulations" << endl;
int num;
cin >> num;
int sum(0);
for (int i = 0; i < num; ++i)
sum += test();
cout << double(sum) / double(num) << endl;
return 0;
}
答案 0 :(得分:0)
我会提出一些想法。可能不是一个确定的答案。
首先,我想知道:如果你预先计算出一个“洗牌”的飞机座位列表,那么这会有所帮助吗?这个想法是:当一名乘客试图坐在他/她的座位上并发现它被占用时,你只需从列表中弹出值,直到找到一个未被占用而不是调用random()的值。您可以将它们弹出,因为您不希望以后的乘客在考虑这些(占用的)座位时浪费时间。这意味着您要避免在随机数生成器持续生成占用席位的行尾附近出现问题。 (虽然,不是你的,我看到了,因为当指定的座位被占用时你确定地找到了一个空置的座位)。鉴于座位分配的这种混乱列表,评估原始问题非常快速和容易。
真正的问题是生成这个“混乱”列表与原始列表完全相同(对于0 #99中的票证#,在插槽中放置票证#(随机)。它是否被占用?等等)所以因为生成一个很好的混乱的座位分配列表与原始问题具有相同的复杂性,有没有一种方法可以简化这么多次的操作?
这让我想到了第二个想法:一旦你有一个这样的洗牌列表,有很多方法可以创建其他的,比100个额外的random()调用容易得多。例如,只需交换两个值。结果列表表示问题的不同运行,乘客的选择略有不同。这样做很多次,你会得到许多不同的运行。
但我不能完全回答的部分是如何确保你得到的样本有一个很好的问题空间样本(monte carlo必须给你很好的结果)。我必须把它留给其他人。