squee_spoon的神奇预言

来源:互联网 发布:舆情监测软件softxy 编辑:程序博客网 时间:2024/06/09 21:03

  近日,举世瞩目的人机大战李世石九段对阵Google AlphaGo在首尔四季酒店进行。

  假设人机大战将进行n盘,已知AI单局的胜率为p%,每局比赛互不影响,AI不会在比完全部n局比赛前增强。人工智能爱好者squee_spoon支持AI获胜,他与朋友打赌AI至少会获得k盘的胜利,如果AI获胜盘数大于等于k,squee_spoon将获得a元,否则他将失去a元。但是,在每一盘比完之后(最后一盘除外),squee_spoon可以向朋友支付b元来使k减少1(当然在任何时候,k必须非负,前n-1局各有一次下调机会)。请问如果squee_spoon使用最优策略,他得到钱数的期望是多少。


  这是一个作者实际遇到的情况改编成的算法题,解法是概率dp。

  状态dp(i,j,k)表示“处于已经打了i盘,获胜了j盘,修改了k次的情况下,获得钱数的期望”,再强调一次,是处于某种特定情况下的期望。

  首先,容易发现i=n的情况是可以直接求出的,因为此时已经打完了全部n盘,胜负已定。若j>=K-k(K是题目给的那个k),squee_spoon获胜,他得到a元且向朋友支付了b*k元;若j<K-k,squee_spoon失败,他失去a元且向朋友支付了b*k元。

  这样我们可以倒着dp回去。因为除了最后一局,每局打完都需要作出决策,根据当前形势,要么下调,要么不下调,最优决策当然是选择下调和不下调之中期望较高的那种做法。这两个期望可以根据基本概率和期望公式计算,不管下调还是不下调,下一局AI都存在输和赢两种可能,所以就从下局输和赢的期望乘以相应概率转移过来。

  最后答案就是初始状态,dp(0,0,0),即一局没打,一局没胜,一次也没调整时,得到钱数的期望。

  值得一提的是,0.01^200刚好溢出了64位浮点数,但是实际上使用64位浮点数做也可以,因为会溢出的数过小,不影响答案。


#include <bits/stdc++.h>#include <unordered_map>   using namespace std;  #define ll long long#define type long double  type dp[210][210][210]; //打了几把 赢了几把 修正几次 int n,K,pp,a,b;type p;  int main(){    while(cin>>n>>K>>pp>>a>>b){        p = pp/100.0;        for(int i=n;i>=0;i--){            for(int j=i;j>=0;j--){                for(int k=min(n-1,i);k>=0;k--){                    if(i==n){                    //打完的情况,胜负已定,直接算出得到的钱数                         if(j+k>=K){                            dp[i][j][k] = a-k*b;                        }else{                            dp[i][j][k] = -a-k*b;                        }                    }else{                        if(i>0){                        //修正与不修正中,选择期望高的做法。无论哪种做法,下一把都有可能赢或输                             dp[i][j][k] = max(dp[i+1][j+1][k]*p+dp[i+1][j][k]*(1-p),                                dp[i+1][j+1][k+1]*p+dp[i+1][j][k+1]*(1-p));                        }else{                        //没打的时候不能修正                             dp[i][j][k] = dp[i+1][j+1][k]*p+dp[i+1][j][k]*(1-p);                        }                                              }                }            }        }        double ans = dp[0][0][0];        printf("%.6f\n",ans);    }    return 0;}


0 0