ZZ tp://www.cppblog.com/proyao/archive/2009/07/19/90527.aspx
『题目大意』
一次比赛中,共M道题,T个队,p[i][j]表示队i解出题j的概率;问每队至少解出一题且
冠军队至少解出N道题的概率。
『算法』
设a[i][j][k]表示第i队在前j道题中共解出k道题的概率,易得a[i][j][k]有如下递推
关系(另需考虑边界条件):
a[i][j][k] = a[i][j-1][k-1] * p[i][j] + a[i][j-1][k] * (1-p[i][j])
设s[i][j]表示a[i][M][0] + a[i][M][1] + ... + a[i][M][j]
问题的解可以转化为:每队均至少做一题的概率(用P1表示)减去每队做题数均在1到N-1
之间的概率(用P2表示)。
P1 = (s[1][M] - s[1][0])*(s[2][M]-s[2][0])*...*(s[T][M]-s[T][0])
P2 = (s[1][N-1] - s[1][0])*(s[2][N-1]-s[2][0])*...*(s[T][N-1]-s[T][0])
『算法复杂度』
O(T*M^2)
int i = 0;
int j =0;
dp[0][0]=1.0;
double sum[32]={1.0};
for(i=1;i<=m;i++)
{
sum[i]=1.0;
for(j=1;j<=i;j++)
sum[i] *= (1-p[j]);
}
for(i=1;i<=m;i++)
dp[i][0]= sum[i];
for(i=1;i<=m;i++)
for(j=1;j<=i;j++)
{
dp[i][j] = dp[i-1][j]*(1-p[i]) + dp[i-1][j-1]*p[i];
// printf("dp[%d][%d] = %.3f/n",i,j,dp[i][j]);
}
for(i=0;i<=m;i++)
{
sum[i]=0;
for(j=0;j<=i;j++)
sum[i] +=dp[m][j];
}
p1*=sum[m]-sum[0];//当前队至少做一道题的概率
p2*=sum[n-1]-sum[0];//做1~n-1道题的概率
//cout<<p1<<" "<<p2<<endl;
}
int main()
{
int m,t,n;
cin>>m;
cin>>t;
cin>>n;
int i = 0;
int j = 0;
while(m || t || n)
{
memset(dp,0,sizeof(dp));
memset(p,0,sizeof(p));
p1=1.0;
p2=1.0;
for(i=1;i<=t;i++)
{
for(j=1;j<=m;j++)
cin>>p[j];
dp_pro(m,n);
}
printf("%.3f/n",p1-p2);
//p1-p2就是在每个队至少作对一道题的情况下除去每个队都做了(1~n-1)道题的补集。
//即为至少有一个对做了n-1道题
cin>>m;
cin>>t;
cin>>n;
}
}