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]); } }