BUAA 1321 逃课

一开始我还在那里想用组合公式做,就是把所有的从连续为M 到N 所有的可能都写一下,可是根本都不行。一个是数太大,一个是情况太多了。今天看见AV_VON的解题报告,原来,原来是DP啊

    我们根据他的数据要求开一个数组,大小为2001, dp[2001]。这个数组用来存放子问题的解,比如dp[i]就代表投完第i个硬币时,已有连续m个正面的概率。具体假如m是2,dp[0],dp[1]肯定0,因为投币0次或1次不可能出现连续两次正面。

分三种情况讨论:

1. n小于m,即dp数组下标i要小于m的时候,概率值都为0,原因如上所述。

2. 下标i等于m,也就是说n等m,投多少次刚好多少次是正面,这个概率是0.5的m次方

3. 下标i大于m,即n大于m的时候,这个又要分两种情况,概率是这两种情况之和:

    (1). 在i之前已经有m次连续了,如果恰好前面第i-1个是连续m次,那第i次如果是正面的话就是连续m+1次符合题目要求,如果第i次是反面的话那恰好就是m次也满足题目,也就是说他第i次无论是正面还是反面都满足条件,所以dp[i]的概率第一种情况由dp[i-1]组成。

    (2). 第i次的时候恰好连续了m次,也就是说他前面m-1次都是正面,那他前面m次的那次是必须是一个反面,否则不能刚好在第i次的时候连续m次正面了。他前面m次的那次是一个反面,那个反面的前一次有连续m次的概率是dp[i-(m+1)],那他没有连续m次正面的概率是1-dp[i-(m+1)],他后面的那次是反面,所以概率是0.5然后接着有m次的0.5概率,即总共是0.5的m+1次方。第二种情况的概率是:dp[i-(m+1)]*pow(0.5, m)

所以第三种情况的概率是他们两个之和:dp[i-1]+dp[i-(m+1)]*pow(0.5, m)

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<math.h>
using namespace std;
int main()
{
    double dp[2011];
    int n,m;
    int i;
    while(cin>>n>>m,n+m)
    {
        for(i=0;i<m;i++)
        dp[i]=0;
        dp[m]=pow(0.5,m);
        for(i=m+1;i<=n;i++)
        dp[i]=dp[i-1]+(1-dp[i-m-1])*pow(0.5,m+1);
        printf("%.2lf\n",dp[n]);
    }

}

  


posted @ 2011-11-27 21:50  AC_Girl  阅读(174)  评论(0编辑  收藏  举报