动态规划求解抛硬币概率问题

题目:

帕秋莉大人的户外运动计划
Time Limit: 1000 ms Memory Limit: 65536 kB
Solved: 48 Tried: 272
Description
帕秋莉大人总是足不出户呢,这样怎么能行呢?于是咲夜找到帕秋莉大人,希望她能每天外出锻炼一段时间。当然,帕秋莉大人断然拒绝了。在咲夜的再三劝说下,帕秋莉大人答应了接下来接近一个月时间的训练计划,但是——帕秋莉大人怎么可能认真执行呢?帕秋莉大人每天会扔n次色子,只有当扔出了至少m次连续的大于3的数时,她才会真正执行训练计划。那么,现在告诉你每天帕秋莉大人扔色子的次数n,和最少连续的大于3数的次数m,你能算出帕秋莉大人每天外出运动的概率么?
注意:色子的点数是1~6,假设每次扔色子出现每种点数的概率都是相等的。
 
Input

读入的第一行是帕秋莉大人的训练计划持续天数T。接下来T行每一行都是某一天帕秋莉大人扔色子的次数n,和最少连续的大于3数的次数m。(1<=m<=n<=10 并且 m<=6)

 Output
输出T行,每行输出帕秋莉大人当天外出运动的概率,四舍五入到两位小数。
 Sample Input
3
2 1
3 2
10 4
 Sample Output
0.75
0.38
0.25

 Source
完全で潇洒なメイド
方法一
View Code
 1 #include<stdio.h>
2 #include<stdlib.h>
3 double dp[12][12];
4 int main(void)
5 {
6 int i,j,T,n,m;
7 scanf("%d",&T);
8 while(T--)
9 {
10 scanf("%d %d",&n,&m);
11 for(i=0;i<=n;i++)
12 {
13 for(j=0;j<=m;j++)
14 {
15 dp[i][j]=0;
16 }
17 }
18 dp[0][0]=1.0;
19 for(i=1;i<=n;i++)
20 {
21 for(j=0;j<m;j++)
22 {
23 if(j>0)dp[i][j]=dp[i-1][j-1]*0.5;
24 dp[i][0]+=dp[i-1][j]*0.5;
25 }
26 }
27 double ans=1.0;
28 for(i=0;i<m;i++)
29 ans-=dp[n][i];
30 printf("%.2f\n",ans);
31 }
32 return 0;
33 }

方法二:
View Code
 1 #include <iostream>
2 #include <iomanip>
3 #include <cmath>
4 using namespace std;
5
6 int main()
7 {
8 //用动态规划解这道题
9 double r[2001];
10 //r[i]代表投完第i个硬币时,已有连续m个正面的概率。
11 int n,m;
12 cin>>n>>m;
13 while(n!=0 && m!=0)
14 {
15 for(int i=0;i<m;i++)
16 r[i]=0;//当投币次数小于m时,自然不可能有m个正面。
17 r[m]=pow(0.5,m);//投币次数为m,全是正面。
18 for(int i=m+1;i<=n;i++)
19 r[i]=r[i-1]+(1-r[i-m-1])*pow(0.5,m+1);
20 //投完第i个硬币时,已有连续m个正面的情况分为两种:
21 //1.投第i个之前已经有连续m个正面,概率为r[i-1]。
22 //2.投完第i个时恰好有连续m个正面,这连续m个正面的前面一次是反面,
23 // 这m+1次确定情况的概率是1/2的m+1次方;
24 // 这m+1次以前没有连续m个正面的概率为1-r[i-(m+1)]。
25 // 所以投完第i个时恰好有连续m个正面的概率为(1-r[i-m-1])*pow(0.5,m+1)。
26 cout<<fixed<<setprecision(2)<<r[n]<<endl;
27 cin>>n>>m;
28 }
29 return 0;
30 }

你可能感兴趣的:(动态规划)