原题:
Mikael likes to gamble, and as you know, you can place bets on almost anything these days. A
particular thing that has recently caught Mikael’s interest is the length of the longest winning streak of a team during a season (i.e. the highest number of consecutive games won). In order to be able to make smarter bets, Mikael has asked you to write a program to help him compute the expected value of the longest winning streak of his favourite teams.
In general, the probability that a team wins a game depends on a lot of different factors, such as
whether they’re the home team, whether some key player is injured, and so on. For the first prototype of the program, however, we simplify this, and assume that all games have the same fixed probability p of being won, and that the result of a game does not affect the win probability for subsequent games. The expected value of the longest streak is the average of the longest streak in all possible outcomes of all games in a season, weighted by their probability. For instance, assume that the season consists of only three games, and that p = 0.4. There are eight different outcomes, which we can represent by a string of ‘W’:s and ‘L’:s, indicating which games were won and which games were lost (for example, ‘WLW’indicates that the team won the first and the third game, but lost the second). The possible results of the season are:
Result LLL LLW LWL LWW WLL WLW WWL WWW
Probability 0.216 0.144 0.144 0.096 0.144 0.096 0.096 0.064
Streak 0 1 1 2 1 1 2 3
In this case, the expected length of the longest winning streak becomes
0.216 · 0 + 0.144 · 1 + 0.144 · 1 + 0.096 · 2 + 0.144 · 1 + 0.096 · 1 + 0.096 · 2 + 0.064 · 3 = 1.104
Input
Several test cases (at most 40), each containing an integer 1 ≤ n ≤ 500 giving the number of games in a season, and a floating point number 0 ≤ p ≤ 1, the win probability. Input is terminated by a case where n = 0, which should not be processed.
Output
For each test case, give the expected length of the longest winning streak. The answer should be given as a floating point number with an absolute error of at most 10−4.
Sample Input
3 0.4
10 0.75
0 0.5
Sample Output
1.104000
5.068090
大意:
给你一个数n和一个浮点数p,表示一个人赌了n次,每次赢的概率是p。现在问你连续获胜的期望是多少?
#include <bits/stdc++.h>
using namespace std;
int n;
double PowP[505],dp[505][505],p;
int main()
{
ios::sync_with_stdio(false);
while(cin>>n>>p,n)
{
PowP[0]=1;
for(int i=1;i<=n;i++)
PowP[i]=PowP[i-1]*p;
for(int i=0;i<=n;i++)
dp[0][i]=1;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=n;j++)
{
dp[i][j]=dp[i-1][j];
if(j==i-1)
dp[i][j]-=PowP[j+1];//减去dp[i-1][j]当中有j个连续的w时的情况
else
{
if(j<i-1)
dp[i][j]-=dp[i-j-2][j]*(1-p)*PowP[j+1];//连续的j个w和一个l的情况
}
}
}
double ans=0;
for(int i=1;i<=n;i++)
ans+=i*(dp[n][i]-dp[n][i-1]);
cout<<fixed<<setprecision(6)<<ans<<endl;
}
return 0;
}
解答:
这题刚看到的时候寻思用暴力,结果一看数据里有500个数,肯定不可以。想到用动态规划和递推求解,状态想出来了,可是转移过程死活想不出来,后来看别人的题解才明白。这题真是6
代码参考这位朋友的博客http://www.cnblogs.com/staginner/archive/2011/12/14/2287150.html
首先设置dp[i][j]表示赌了n次,连续胜利不超过j次,我当时想的时候也就是想到这里,剩下的想不来了= =
接下来转移方程,如果这个人赌了第i次,结果无论是赢还是输没和之前的结果产生连续的胜利次数超过j次,就不用去管,直接把上一次的结果转移过来即可:dp[i][j]=dp[i-1][j]
如果和上一次的产生连续的胜利次数超过j,那就要把不合理的情况的概率减去。
这里也是又两个情况,一个是赌了i次全是胜利的情况也就是i-1==j(这里是i-1的状态,因为要向i状态转移),那么dp[i][j]-=PowP[j+1](超过了j次胜利,所以是j+1)。如果i次当中没有全部胜利,但是也出现了连续j次的胜利,也就i>j+1时,就需要前面有连续的j个w,同时在前面必须有一个l。dp[i][j]-=dp[i-j-2][j]×(1-p)×PowP[j+1];
最后dp[i][[j]-dp[i][j-1]去掉重复的部分然后乘以赌博次数i并累加就是期望。