Monte Carlo Sims - 请检查我的算法

时间:2011-05-08 13:20:03

标签: c++ algorithm

基本上,问题模拟了以下内容:

有一个有50个绿球和50个红球的骨灰盒。

我被允许从瓮中挑球,没有替换,遵守以下规则:对于每一个挑选的红球,我输了一美元,因为每一个选中的绿球,我都会获得一美元。

我可以随时停止挑选。最糟糕的情况是我选择全部100和净0。

问题是提出一个最佳停止策略,并创建一个程序来计算策略的预期价值。

我的策略是继续挑球,而选择另一球的预期值是正值。

也就是说,停止规则是DYNAMIC。

在Latex中,这是图像中的递归公式:

http://i.stack.imgur.com/fnzYk.jpg

#include <stdio.h>
#include <math.h>
#include <stdlib.h>



double ExpectedValue(double, double);
double max(double, double);

main() {

double g = 50;
double r = 50;


double EV = ExpectedValue(g, r);

printf ("%f\n\n", EV);

system("PAUSE");

}


double ExpectedValue(double g, double r){

double p =  (g / (g + r));

double q = 1 - p;

if (g == 0)

return r;

if (r == 0)

return 0;

double E_gr = max ((p * ExpectedValue (g - 1, r)) + (q * ExpectedValue (g, r - 1)), (r - g));

return E_gr; 

}

double max(double a, double b){

if (a > b)
return a;

else return b;
}

我让它运行30分钟,它仍在运行。 对于小的g和r值,可以非常快速地计算解。我做错了什么?

非常感谢任何帮助!

3 个答案:

答案 0 :(得分:4)

你的算法很好,但是你在浪费信息。对于某个对(g, r),您可以计算它的ExpectedValue,然后将该信息丢弃。通常使用递归算法记住先前计算的值可以加快 LOT

以下代码在眨眼之间运行。例如,对于g = r = 5000,它会在1秒内计算36.900218。它记得以前的ExpectedValue(g, r)计算,以防止不必要的递归和重新计算。

#include <stdio.h>
#include <stdlib.h>

double ExpectedValue(int g, int r, double ***expectedvalues);
inline double max(double, double);

int main(int argc, char *argv[]) {
    int g = 50;
    int r = 50;
    int i, j;

    double **expectedvalues = malloc(sizeof(double*) * (g+1));

    // initialise
    for (i = 0; i < (g+1); i++) {
        expectedvalues[i] = malloc(sizeof(double) * (r+1));
        for (j = 0; j < (r+1); j++) {
            expectedvalues[i][j] = -1.0;
        }
    }

    double EV = ExpectedValue(g, r, &expectedvalues);
    printf("%f\n\n", EV);

    // free memory
    for (i = 0; i < (g+1); i++) free(expectedvalues[i]);
    free(expectedvalues);

    return 0;
}

double ExpectedValue(int g, int r, double ***expectedvalues) {
    if (g == 0) return r;
    if (r == 0) return 0;

    // did we calculate this before? If yes, then return that value
    if ((*expectedvalues)[g][r] != -1.0) return (*expectedvalues)[g][r];

    double p = (double) g / (g + r);
    double E_gr = max(p * ExpectedValue(g-1, r, expectedvalues) + (1.0-p) * ExpectedValue(g, r-1, expectedvalues), (double) (r-g));

    // store value for later lookup
    (*expectedvalues)[g][r] = E_gr;

    return E_gr;
}

double max(double a, double b) {
    if (a > b) return a;
    else return b;
}

答案 1 :(得分:2)

在我看来,这是正确的,但却是直截了当的解决方案。

以下是您可以做的事情:

  • 消除递归!
  • 消除对ExpectedValue
  • 的重新计算
  • 并行化代码
  • 阅读此[lecture notes]。它绝对有用

我可以提供一些代码示例,但这不公平。

答案 2 :(得分:2)

粗略地说,在球门上添加一个球会使你需要对ExpectedValue进行的召唤次数加倍(让我们不要对边界条件进行狡辩)。这被称为O(e n ),它可以使地球上最强大的计算机瘫痪。

问题是你一遍又一遍地计算相同的值。保留一张ExpectedValue(r,g)的表格并随时填写,这样您就不必多次计算相同的值。然后你将在O(n 2 )工作,这要快得多。