游戏(第二次触碰概率dp已经有了感觉了!!!)

游戏

【问题描述】
Alice和Bob两个人正在玩一个游戏,游戏有很多种任务,难度为p的任务(p是正整数),有12p 的概率完成并得到12p−分,如果完成不了,得0分。一开始每人都是0分,从Alice开始轮流做任务,她可以选择任意一个任务来做;而Bob只会做难度为1的任务。只要其中有一个人达到n分,即算作那个人胜利。求Alice采取最优策略的情况下获胜的概率。
【输入】
一个正整数n,含义如题目所述。
【输出】
一个数,表示Alice获胜的概率,保留6位小数。
【输入输出样例】
game.in
1
2
game.out
0.666667
0.651852

题解:
1.拿到这道题感觉像是递推,A赢B输,A输B输——>A赢B输,减去B赢的概率
2.但是……因为有p的枚举,这道题就变成了无限递推,然后zch大佬用了一招十分玄妙的计时器大发卡时间偏分
3.然后不约而同地打了样例上去 10分。

——————————————废话分割线——————————————

先给出方程

f[i][j]=max(P*(f[i-k][j-1]+f[i-k][j])+(1-P)*(f[i][j-1]+f[i][j]))

注释:
f[i][j]表示达到赢A还需i分,B还需j分的这种情况的当前概率
P是代表着当前这种情况的概率,设概率P为(2的p次方)分之一,则设分数k为2的p次方-1.即设P为这种情况下,A赢得概率,那么自然,1-P就是输的概率 了
很容易可以得到P和k的转换关系,所以我们枚举k,然后这道题用记忆化搜索可能更容易理解,
因为我们搜索下去的时候,当x(即i)到达0时,说明这种情况下A已经赢了,所以返回值是1(即100%),但如果y比x先到达1,那么这种情况下A必输无疑。

       if (x<=0)
          return 1.0;
       if (y==0)
          return 0.0;
       if (f[x][y]>=0)
          return f[x][y];

这一段处理用记忆化是很方便的。

然后我其实本来不会这道题,因为接触不多,然后听了题解还是有疑惑,主要是在 为什么算A胜利的时候,要把(x-k,y-1)这个情况也算进去,因为我实在不理解为什么AB能够同时胜利,但其实没什么关系的因为我们是把x放在前面判断,无论如何该种情况都算是A胜利,无需钻牛角尖。

#include<bits/stdc++.h>
using namespace std;


const int maxn=1001;
int n;
double f[maxn][maxn];

double dp(int x,int y)
{
       if (x<=0)
          return 1.0;
       if (y==0)
          return 0.0;
       if (f[x][y]>=0)
          return f[x][y];

       for (int k=1,p=2;k<=1024;p<<=1,k<<=1)
       {
           double tmp;
           tmp=dp(x-k,y-1)+dp(x-k,y)+(double)(p-1)*dp(x,y-1);
           tmp/=(double)(p+1);//乘以概率 
           f[x][y]=max(f[x][y],tmp);
       }
       return f[x][y];
}

int main()
{
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);

    scanf("%d",&n);
    for (int i=0;i<=1000;i++)
        for (int j=0;j<=1000;j++)
            f[i][j]=-1000;
    cout<<setprecision(6)<<fixed<<dp(n,n)<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/beautiful_CXW/article/details/81132236
今日推荐