您的位置:首页 > 其它

POJ2151- Check the difficulty of problems(概率DP)

2016-01-15 19:17 429 查看
http://poj.org/problem?id=2151

给m,m道题

t,t个队伍

n,必须有队伍ac数超过n题

求  满足以下2个条件的概率

1、所有队伍至少过1题,

2、冠军队伍至少过n题

dp[i][j][k] 表示 第i只队伍做了前j道题,过了k题 

那么可以得到   dp[i][j][k]=dp[i][j-1][k-1]*(tm[i][j])+dp[i][j-1][k]*(1-tm[i][j]);  

当然要预处理一下dp[i][j][0]这些边界

得到dp[i][j][k]后,可以求 s[i][k] 表示第i队做了小于等于k题的概率 

//s[i][k]= dp[i][m][0]+dp[i][m][1]+...+ dp[i][m][k];
//=s[i][k-1]+dp[i][m][k];

同样要记得预处理边界 s[i][0]=dp[i][m][0];

那么最后 全部人至少作出1道题的概率是 p1=(1-s[ 1 ][0])*(1-s[ 2 ][0])*.....*(1-s[ t ][0])

全部人只做出(1至N-1)道题的概率p2= (s[1][N-1]-s[1][0])* ...*(s[i][N-1]-s[i][0])

p1-p2 得到的就是 所有人至少做出一道,并且有人至少做了n道的概率了。

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;

double tm[1005][35];
int cun[1005];
double dp[1005][35][35];
double s[1005][35];
int main()
{
int m,t,n;
while(scanf("%d%d%d",&m,&t,&n)!=EOF)
{
int i,j,k;
if (!m&&!t&&!n) break;
memset(dp,0,sizeof(dp));
memset(s,0,sizeof(s));
memset(cun,0,sizeof(cun));
for (i=1;i<=t;i++)
{
for (j=1;j<=m;j++)
{
scanf("%lf",&tm[i][j]);
if (tm[i][j]>0) cun[i]++;
}
}
int flag=0;
for (i=1;i<=t;i++)
{
if (cun[i]>=n) flag=1;
if (cun[i]==0){flag=0;break;}
}
if (!flag) {printf("0.000\n"); continue;}
//初始化

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-tm[i][j]);

}
s[i][0]=dp[i][m][0];
}

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]*(tm[i][j])+dp[i][j-1][k]*(1-tm[i][j]);
}
}
}
//s[i][k]第i队做了不超过k题的概率
//s[i][k]= dp[i][m][0]+dp[i][m][1]+...+ dp[i][m][k];
//=s[i][k-1]+dp[i][m][k];
for (i=1;i<=t;i++)
{
for (j=1;j<=m;j++)
{
s[i][j]=s[i][j-1]+dp[i][m][j];
}
}

double p1=1;
double p2=1;
for (i=1;i<=t;i++)
{
p1*=(1-s[i][0]);
p2*=s[i][n-1]-s[i][0];
}

printf("%.3lf\n",p1-p2);
}
return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: