题目:
题意:
ACM比赛中,共M道题,T个队,pij表示第i队解出第j题的概率
问每队至少解出一题且冠军队至少解出N道题的概率。
题解:
学会“至少”这个词的转化
dp[i][j][k]表示第i个队前j个题做对k个的概率
dp[i][j][k]=dp[i][j-1][k-1]*p[j][k]+dp[i][j-1][k]*(1-p[j][k]);
先初始化算出dp[i][0][0]和dp[i][j][0](因为k==0的情况只能在这里处理)
设a[i][k]表示第i队做出的题小于等于k的概率
则a[i][k]=dp[i][M][0]+dp[i][M][1]+``````+dp[i][M][k];
则每个队至少做出一道题概率为P1=(1-a[1][0])*(1-a[2][0])*```(1-a[T][0]);
每个队做出的题数都在1~N-1的概率为P2=(a[1][N-1]-a[1][0])*(a[2][N-1]-a[2][0])*```(a[T][N-1]-a[T][0]);
最后的答案就是P1-P2
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
double a[1005][50],dp[1005][50][50];
int main()
{
int i,j,m,t,n,k;
while (scanf("%d%d%d",&m,&t,&n))
{
if (m==0 && t==0 && n==0) return 0;
double p1=1.0,p2=1.0;
if (n==1) p2=0;
memset(dp,0,sizeof(dp));
for (i=1;i<=t;i++)
for (j=1;j<=m;j++)
scanf("%lf",&a[i][j]);
for (i=1;i<=t;i++)
{
dp[i][0][0]=1;
for (j=1;j<=m;j++) dp[i][j][0]=dp[i][j-1][0]*(1-a[i][j]);
}
for (i=1;i<=t;i++)
for (j=1;j<=m;j++)
for (k=1;k<=j;k++)
dp[i][j][k]=dp[i][j-1][k]*(1-a[i][j])+dp[i][j-1][k-1]*a[i][j];
memset(a,0,sizeof(a));
for (i=1;i<=t;i++)
for (j=0;j<=m;j++)
if (j!=0) a[i][j]=a[i][j-1]+dp[i][m][j];
else a[i][j]=dp[i][m][0];//a[i][j]表示第i队做对小于等于j道题的概率
for (i=1;i<=t;i++)
{
p1*=(1-a[i][0]);
p2*=(a[i][n-1]-a[i][0]);
}
printf("%.3lf\n",p1-p2);
}
}