LightOJ 1395 A Dangerous Maze (II) 期望DP

A Dangerous Maze (II) LightOJ - 1395

这个题是 LightOJ 1027 A Dangerous Maze 基础概率DP 的加强版。

nn 个门,其中有些门通过之后, xix_i 分钟后会回到原点,另一些门通过后,xix_i 分钟后会出去,现在能够记住最近的 KK 次选择,下次选择时会从剩下的未在这 KK 次选择中出现的门进行选择,问出去的期望时间。

首先这 KK 次记住的肯定是未出去的门,因为假如出去的话就已经结束了,不需要再进行选择,定义出去的门为集合 A\mathcal{A},返回的门为集合 B\mathcal{B},用 dp[i]dp[i] 表示记忆了 ii 个未出去的门对应的期望,分两种情况进行讨论:

(1)假如 KBK\ge|\mathcal{B}|,也就是说记忆的 KK 个经验能够包括到所有回来的门,则 dp[B]=1AiAxidp[|\mathcal{B}|]=\dfrac{1}{|\mathcal{A}|}\sum\limits_{i\in\mathcal{A}}x_i,即此时的期望就等于从能够出去的门中选一个之后的期望时间。此时再推 j<Bj<|\mathcal{B}| 时对应的 dpdp 值,此时 dp[j]=1njiAxi+1nj(iBC(xi+dp[j+1]))dp[j]=\dfrac{1}{n-j}\sum\limits_{i\in\mathcal{A}}x_i+\dfrac{1}{n-j}(\sum\limits_{i\in\mathcal{B}\setminus\mathcal{C}}(x_i+dp[j+1])),其中 C\mathcal{C} 表示已经选择过的 jj 个不能出去的门的集合,BC\mathcal{B}\setminus\mathcal{C} 表示还未选择的不能出去的门的集合,因为 C\mathcal{C} 是一个随机选择出来的集合,可以证明:

iBCxi=BCBiBxi \sum_{i\in\mathcal{B}\setminus\mathcal{C}}x_i=\frac{|\mathcal{B}\setminus\mathcal{C}|}{|\mathcal{B}|}\sum_{i\in\mathcal{B}}x_i

因此:

dp[j]=1njiAxi+BCnj(iBxiB+dp[j+1])dp[j]=1njiAxi+Bjnj(iBxiB+dp[j+1]) \begin{aligned} dp[j]&=\frac{1}{n-j}\sum_{i\in\mathcal{A}}x_i+\frac{|\mathcal{B}\setminus\mathcal{C}|}{n-j}(\frac{\sum_{i\in\mathcal{B}}x_i}{|\mathcal{B}|}+dp[j+1])\\ dp[j]&=\frac{1}{n-j}\sum_{i\in\mathcal{A}}x_i+\frac{|\mathcal{B}|-j}{n-j}(\frac{\sum_{i\in\mathcal{B}}x_i}{|\mathcal{B}|}+dp[j+1])\\ \end{aligned}
逆推即可以求得 dp[0]dp[0]

(2)假如 K<BK<|\mathcal{B}|,也就是说并不能完全记住所有的返回门,那么 j=Kj=K 时:

dp[K]=1nKiAxi+BKnK(iBxiB+dp[K])dp[K]=1nBiAxi+BKnBiBxiB \begin{aligned} dp[K]&=\frac{1}{n-K}\sum_{i\in\mathcal{A}}x_i+\frac{|\mathcal{B}|-K}{n-K}(\frac{\sum_{i\in\mathcal{B}}x_i}{|\mathcal{B}|}+dp[K])\\ dp[K]&=\frac{1}{n-|\mathcal{B}|}\sum_{i\in\mathcal{A}}x_i+\frac{|\mathcal{B}|-K}{n-|\mathcal{B}|}\frac{\sum_{i\in\mathcal{B}}x_i}{|\mathcal{B}|}\\ \end{aligned}

j<Kj<K 时:

dp[j]=1njiAxi+Bjnj(iBxiB+dp[j+1]) dp[j]=\frac{1}{n-j}\sum_{i\in\mathcal{A}}x_i+\frac{|\mathcal{B}|-j}{n-j}(\frac{\sum_{i\in\mathcal{B}}x_i}{|\mathcal{B}|}+dp[j+1])

也可以逆推求得 dp[0]dp[0]

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
//#define WINE
using namespace std;
int T,iCase,n,K,a,ca,cb,sa,sb;
double res;
int main(){
#ifdef WINE
    freopen("data.in","r",stdin);
#endif
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&K);
        ca=cb=sa=sb=0;
        for(int i=0;i<n;i++){
            scanf("%d",&a);
            if(a>0)ca++,sa+=a;
            else cb++,sb+=-a;
        }
        if(cb==n){
            printf("Case %d: -1\n",++iCase);
            continue;
        }
        K=min(K,cb);
        if(K<cb)res=1.0/(n-cb)*sa+1.0*(cb-K)*sb/(n-cb)/cb;
        else res=1.0*sa/ca;
        for(int j=K-1;j>=0;j--)
            res=1.0*sa/(n-j)+1.0*(cb-j)/(n-j)*(1.0*sb/cb+res);
        printf("Case %d: %.8lf\n",++iCase,res);
    }
    return 0;
}

在这里插入图片描述

posted @ 2020-03-26 22:22  winechord  阅读(105)  评论(0编辑  收藏  举报