概率DP

 

题目描述

小迟最近去参加了一个锦标赛,这个锦标赛总共有n轮比赛,最终成绩由这n轮比赛中赢的轮数决定。至于小迟每一轮比赛的胜利概率,则取决于他在该轮比赛之前的战绩。也就是说,如果小迟在第i轮比赛选择积极应战,并且前i-1轮比赛中取得了j胜的话,那么第i轮比赛的胜利概率为p[i][j],这里我们保证了一点就是对于同一个i,p[i][j]关于j的上升保持单调不上升(也就是说p[i][j]p[i][j+1])。
小迟观察到这个规则之后,想到了一个可能可以使他最终成绩更优的犯法,就是在某些轮比赛采取第二种策略,故意求败,也就是以100%的概率输掉该轮比赛,从而使自己在后面能够遇到更容易对付的对手。
小迟现在已经看到了整个p数组,小迟希望你能告诉他一个最优的策略,使得他能最大化他的期望赢的轮数。这里,定义一下期望。假设我们要求一个事件A的期望,那么假如事件A以Pi的概率结果为i,那么事件A的期望则是i*Pi的和,大概的含义就是结果值关于概率的一个加权平均数。

 

输入

第一行为轮数n,n为正整数。
接下来的n行,第i行有i个实数,表示对应的p[i]0],....p[i][i-1]

 

输出

一行一个实数,表示最优策略下期望赢的轮数,保留两位小数。

 

样例输入

复制样例数据

2
0.5
0.5 0.5

样例输出

1.00

 

提示

由于我们看到对于第i轮,无论之前战绩如何,胜率都是相同的,因此我们的最优策略应当是每一轮努力求胜。
然后,第一轮,如果我们赢了,概率为0.5,输了的概率也为0.5。
如果第一轮赢了,第二轮又赢了,概率为0.5*0.5=0.25,赢两盘;
如果第一轮赢了,第二轮输了,概率为0.5*(1-0.5)=0.25,赢一盘;
如果第一轮输了,第二轮赢了,概率为(1-0.5)*0.5=0.25,赢一盘;
如果两轮都输了,概率为(1-0.5)*(1-0.5)=0.25,赢零盘。
故期望赢的轮数为0.25*2+(0.25+0.25)*1+0.25*0=1

对于100%的数据,1≤n≤1000,0≤p[i][j]≤1.

 

 1 /**/
 2 #include 
 3 #include 
 4 #include 
 5 #include 
 6 #include 
 7 #include 
 8 #include 
 9 #include <set>
10 #include 
11 #include <string>
12 #include 
13 #include 
14 
15 typedef long long LL;
16 typedef unsigned long long ULL;
17 using namespace std;
18 const int maxn = 1000 + 24;
19 int n;
20 double p[maxn][maxn];
21 double dp[maxn][maxn];
22 int main()
23 {
24     scanf("%d",&n);
25     for(int i = 1; i <= n; i++)
26         for(int j = 0; j < i; j++)
27             scanf("%lf", &p[i][j]);
28     dp[0][0] = 1;
29     for(int i = 0; i < n; i++)
30         for(int j = 0; j <= i; j++) {
31             dp[i+1][j+1] += dp[i][j] * p[i+1][j];
32             dp[i+1][j] += dp[i][j] * (1 - p[i+1][j]); 
33     }
34     double ans = 0;
35     for(int j = 0; j <= n; j++) ans += j * dp[n][j];
36     printf("%.2lf\n", ans);
37     return 0;
38 }
View Code

 

 由大佬的博客可知,放水是题目中设置的干扰。于是蒟蒻不管它,直接写了。

状态转移方程好像也挺好理解的

第一次在博客园写随笔,好像紧张得写不出话来....就这样吧

 

 

 

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