【poj2151】 Check the difficulty of problems

http://poj.org/problem?id=2151 (题目链接)

题意

  T支队伍,一共M道题,第i支队伍解出第j道题的概率为p[i][j]。问每支队伍至少解出1道题并且解题最多的的队伍至少解出N道题的概率。

Solution

  我终于明白了,这种题目,永远也不要想着去搞清楚样例是怎么算出来的,只要列出你认为正确的dp方程就行了。。

  于是这道题,令${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})}$$

  再令${s_{i,j}}$表示第i个队伍解出的题目数小于等于j道的概率,那么很显然:

$${s_{i,j}=s_{i,j-1}+f_{i,m,j}}$$

  于是每个队伍解出的题目数再范围${1,M}$的概率p1(也就是至少解出一道题):

$${p1=prod_{i=1}^{t}(1-s_{i,0})}$$

  每个队伍解出的题目数在范围${1,N-1}$的概率p2(每个队伍都至少解出一道题,但没有一支队伍解题数大于等于N):

$${p2=prod_{i=1}^{t}(s_{i,N-1}-s_{i,0})}$$

  那么最后的答案:p1-p2

代码

// poj2151
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf 1<<30
#define eps 1e-8
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;

const int maxt=1010,maxm=40;
double f[maxt][maxm][maxm],s[maxt][maxm],p[maxt][maxm];
int n,m,t;

int main() {
	while (scanf("%d%d%d",&m,&t,&n)!=EOF && m && t && n) {
		memset(f,0,sizeof(f));
		for (int i=1;i<=t;i++)
			for (int j=1;j<=m;j++) scanf("%lf",&p[i][j]);
		for (int i=1;i<=t;i++) {
			f[i][0][0]=1;
			for (int j=1;j<=m;j++)
				for (int k=0;k<=j;k++) {
					f[i][j][k]=f[i][j-1][k]*(1-p[i][j]);
					if (k) f[i][j][k]+=f[i][j-1][k-1]*p[i][j];
				}
			s[i][0]=f[i][m][0];
			for (int j=1;j<=m;j++) s[i][j]=s[i][j-1]+f[i][m][j];
		}
		double p1=1,p2=1;
		for (int i=1;i<=t;i++) p1*=1-s[i][0],p2*=(s[i][n-1]-s[i][0]);
		printf("%.3lf
",p1-p2);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/MashiroSky/p/6242038.html