SGU495 Kids and Prizes(DP概率)

    题目描述:有n个盒子,装着东西,m个人取盒子,每次取一个盒子打开,每个盒子的第一个打开者拿走物品,而放回空盒子,以后的人打开了空盒子就没有东西拿。那么问东西被拿走的期望是多少。

    首先这是一个放回的概率,即盒子的总数一直没有变化,都是n,而一个人拿走了东西,下一个人拿到东西的概率就被-1/n 因为一个人最多只能带走一件东西,而盒子总量没有变化,假设第i个人拿走东西的概率是Y[ I ]  没拿走东西的概率是N[ i ],显然两者是对立事件(加和为1),那么可以找到递推关系式:

    Y[ i ] = N[ i -1 ] *Y[ i-1 ] + Y[ i - 1 ] * (Y [ i - 1 ] - 1/n)   // 即两种情况:1.前面一个人没有拿走东西,此时能拿到东西的概率同前一个人不变 2.前面一人拿走了东西,现在i拿到东西的概率就比前一人下降1/n

   N[ i ]=1-Y[ i ]

   那么算出每一个人拿到东西的概率,乘以拿到东西的件数(1件),就是最后的结果

   其实还有一种更方便的算法:每个盒子一直没被选中的概率是P=((n-1)/n)^m,那么被选中的概率是1-P,盒子数是n,每个盒子的权值是1,所以最后的结果是 n*( 1 - p ) * 1

   这题恶心在卡最后的输出,一定是printf("%.10lf",ret) 之前没用。10lf果断WA到死,还一度对第二种方法产生怀疑,弱狗一只飘过,但好处是,两个代码我都实现了。

    第一种方法:

#include<cstdio>
using namespace std;

#define maxn 1000005
double Y[maxn],N[maxn];

int main(){
    int i,j,n,m;
    while(scanf("%d %d",&n,&m)!=EOF){
        Y[1]=1;
        N[1]=0;
        double ret=1;
        for(i=2;i<=m;i++){
            Y[i]=Y[i-1]*N[i-1]+Y[i-1]*(Y[i-1]-1.0/n);
            N[i]=1-Y[i];
            ret+=Y[i];
        }
        printf("%.10lf\n",ret);

    }
}


 

    第二种方法:

#include<cstdio>
using namespace std;

double ac(int n,int m){
    double now=(n-1.0)/n;
    double ret=n;
    while(m){
        if(m&1) ret*=now;
        m>>=1;
        now*=now;
    }
    return n-ret;
}

int main(){
    int n,m;
    while(scanf("%d %d",&n,&m)!=EOF){
        printf("%.10lf\n",ac(n,m));
    }
    return 0;
}


 

你可能感兴趣的:(DP概率)