UVA_11176
这个题目一开始打算去求一共有i个W时连续的W不超过j个的情况总数,但后来发现复杂度n^3一直降不下来,后来看了UVA论坛上的提示,终于写出了n^2的算法。
我们设f[i][j]表示到第i场比赛时连续的W不超过j场的概率,那么最后我们只要用j乘以对应的f[N][j]-f[N][j-1]之后求和即可。
接下来我们考虑状态如何转移,对于i=1,显然f[1][0]=1-P,f[1][i]=1(i>=1),而对于任意一个i>1来讲,实际上第i场比赛要么是W,要么是L,如果不影响连续W的场数的话f[i][j]=f[i-1][j],因为这场是W或者L无所谓。那么什么情况下会影响连续场数呢,显然是i前面有连续的j个W的情况,我们再把出现这种情况的概率减去即可。具体计算的时候需要考虑i==j+1和i>j+1两种情况讨论,因为如果i==j+1,就是前面所有的都是W的情况,而i>j+1时,就需要前面有连续的j个W,同时再前面必须有一个L。
#include<stdio.h>
#include<string.h>
#include<math.h>
#define MAXD 510
int N;
double P, p[MAXD][MAXD], d[MAXD];
void solve()
{
int i, j, k;
double res = 0, temp;
d[0] = 1;
for(i = 1; i <= N; i ++)
d[i] = d[i - 1] * P;
for(i = 0; i <= N; i ++)
p[0][i] = 1;
for(i = 1; i <= N; i ++)
for(j = 0; j <= N; j ++)
{
p[i][j] = p[i - 1][j];
if(j == i - 1)
p[i][j] -= d[j + 1];
else if(j < i - 1)
p[i][j] -= p[i - j - 2][j] * (1 - P) * d[j + 1];
}
for(i = 1; i <= N; i ++)
res += i * (p[N][i] - p[N][i - 1]);
printf("%.6lf\n", res);
}
int main()
{
for(;;)
{
scanf("%d%lf", &N, &P);
if(!N)
break;
solve();
}
return 0;
}