POJ2151

好了现在开始写那个走错门的概率DP

对于概率DP,我之前真的是一无所知,遇到这种题目就直接跪了

其实这道题还是挺适合入门的(很好的体现了各个公式的运用)

题意大概是有T只队伍和M道题目。给出每个队伍解决每道题目的概率,让你求所有队伍均至少做出1题且冠军队伍做出至少N题的概率。

我们设f[i][j][k]表示第i只队伍在前j题中做出k题的概率,则有以下转移:

f[i][j][k]=f[i][j-1][k-1]*p[i][j]+f[i][j-1][k]*(1-p[i][j]);

很好理解吧,第k题做出来和没做出来的概率相加

再设sum[i][j]表示第i只队伍在m道题中做出j题的概率,则:

sum[i][j]=sum[i][j-1]+f[i][m][k];

然后我们想一下,要求所有的队伍做出一题的概率p1就是:

p1*=sum[i][m]-sum[i][0];

但是还要满足最多的队伍做出n题,我们转化一下可以统计出所有队伍均做出1题且都不超过n题的概率p2:

p2*=sum[i][n-1]-sum[i][0];

要满足要求,所以ans就是p1-p2了

#include<cstdio>
using namespace std;
const int M=35,T=1005;
int n,m,t;
double f[T][M][M],p[T][M],sum[T][M],p1,p2;
int main()
{
	register int i,j,k;
	for (;;)
	{
		scanf("%d%d%d",&m,&t,&n);
		if (!m&&!t&&!n) break;
		for (i=1;i<=t;++i)
		for (j=1;j<=m;++j)
		scanf("%lf",&p[i][j]);
		for (i=1;i<=t;++i)
		f[i][0][0]=1;
		for (i=1;i<=t;++i)
		for (j=1;j<=m;++j)
		f[i][j][0]=f[i][j-1][0]*(1-p[i][j]);
		for (i=1;i<=t;++i)
		{
			for (j=1;j<=m;++j)
			for (k=1;k<=j;++k)
			f[i][j][k]=f[i][j-1][k-1]*p[i][j]+f[i][j-1][k]*(1-p[i][j]);	
			for (sum[i][0]=f[i][m][0],k=1;k<=m;++k)
			sum[i][k]=sum[i][k-1]+f[i][m][k];
		}
		for (p1=1,p2=1,i=1;i<=t;++i)
		{
			p1*=(sum[i][m]-sum[i][0]);
			p2*=(sum[i][n-1]-sum[i][0]);
		}
		printf("%.3lf
",p1-p2);		
	}
	return 0;
}
原文地址:https://www.cnblogs.com/cjjsb/p/8728967.html