51nod 1450 闯关游戏 期望dp

题意

一个游戏App由N个小游戏(关卡)构成,将其标记为0,1,2,..N-1。这些小游戏没有相互制约的性质,玩家可以任意时刻玩任意一个小游戏,且每个小游戏可以玩任意多次,一个小游戏玩一次消耗玩家恰好1min的时间。每个小游戏会根据玩家的表现返回3种结果:1)挑战失败;2)挑战成功并获得1颗星;3)挑战成功且获得2颗星。玩家可以多次挑战同一个小游戏,而且系统会记录玩家多次挑战中的最好成绩。(注意:两颗星优于一颗星优于挑战失败。)
这个游戏App通关需要同时满足2个条件:1)N个小游戏的系统记录的最好成绩都是成功;2)这N个小游戏的系统记录成绩中的星星总数至少是M颗。
根据一些统计,一个玩家在任一次玩第i个小游戏时,都会独立的发生以下结果:
* 有(1000 - X[i] - Y[i])*0.001的概率会挑战失败;
* 有 X[i]*0.001 的概率会挑战成功并获得一颗星;
* 有 Y[i]*0.001 的概率会挑战成功并获得两颗星.
其中1<=X[i],Y[i],且X[i]+Y[i]<=1000,且都为整数.
问一个玩家从安装完这个游戏App到这个游戏App通关,最优策略下需要花费时间的期望E。输出E的值,以min为该时间单位。(误差在1e-7内)
1<=N<=2000,N <= M <= 2N

分析

发现自己期望方面菜的抠脚。。。搞了一天才略微搞懂这道题目。

显然是把所有人按照Y从小到大排序,当做到一个位置i,满足剩下的游戏全都要两星才能通关时,就需要不停地做这些游戏直到两星。
设f[i,j]表示前i个游戏抽到j颗星的概率,转移十分显然。
然后直接统计答案即可。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=2005;

int n,m;
pair<int,int> a[N];
double f[N][N*2],s1[N],s2[N];

int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        a[i]=make_pair(y,x);
    }
    sort(a+1,a+n+1);
    for (int i=1;i<=n;i++)
    {
        double x=(double)a[i].second/1000,y=(double)a[i].first/1000;
        double p1=1/(x+y),p2=1/y;
        s1[i]=s1[i-1]+p1;s2[i]=s2[i-1]+p2;
    }
    if (n*2<=m) 
    {
        printf("%.10lf\n",s2[n]);
        return 0;
    }
    f[0][0]=1;
    double ans=0;
    for (int i=1;i<=n;i++)
    {
        double x=(double)a[i].second/1000,y=(double)a[i].first/1000;
        double p1=x/(x+y),p2=1-p1,p=s1[i]+s2[n]-s2[i];
        for (int j=i;j<=n*2;j++)
        {
            f[i][j]=f[i-1][j-1]*p1;
            if (j>1) f[i][j]+=f[i-1][j-2]*p2;
            if ((n-i)*2==m-j) ans+=p*f[i][j];
            if ((n-i)*2<=m-j) f[i][j]=0;
        }
    }
    for (int i=m+1;i<=n*2;i++) ans+=s1[n]*f[n][i];
    printf("%.10lf",ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值