【POJ2151】Check the difficulty of problems(概率DP)

题目:

我是超链接

题意:

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);
	}
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值