POJ 2151 Check the difficulty of problems(概率DP)

题目链接:点击打开链接

题意:ACM比赛中, 有T个队, m道题, 每个队能解出每道题的概率已知, 求每个队至少解出一道题并且冠军队解出至少n道题的概率。

思路:首先, 我们不难想到用d[i][j]表示前i个队, 冠军队解出了j道题的概率。 那么答案就是sum(a[n][j]) j >= n 。  每次转移的代价是, 决策第i个队解决了多少道题, 并且更新j(冠军队的解题数)。 那么难点就在于怎么求出第i个队解出j个题的概率。   我们再求一次DP, 用x[i][j][k]表示,第i个队在前j个题中解出了k个题的概率。  那么转移就是x[i][j][k] = x[i][j-1][k-1] * a[i][j] + x[i][j-1][k] * a[i][j]。 边界条件是:

1.  x[0][0][0] = 1,表示前0个队解出0题,  这是显然的。

2.  还有一个就是x[i][j][0] = (1-a[i][1]) * (1-a[i][2]) * ...... * (1 - a[i][j])。

细节参见代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
typedef long double ld;
const ld eps = 1e-9, PI = 3.1415926535897932384626433832795;
const int mod = 1000000000 + 7;
const int INF = 0x3f3f3f3f;
const int seed = 131;
const ll INF64 = ll(1e18);
const int maxn = 1000 + 10;
int T,n,m,vis[maxn][33],kase = 0;
double a[maxn][33],x[maxn][33][33], d[maxn][33];
double dp(int i, int j) {
    double& ans = d[i][j];
    if(i == T + 1) return j >= n ;
    if(vis[i][j] == kase) return ans;
    vis[i][j] = kase;
    ans = 0;
    bool ok = false;
    for(int k = 1; k <= m; k++) {
        ans += dp(i+1, max(j, k)) * x[i][m][k];
    }
    return ans;
}
int main() {
    while(~scanf("%d%d%d",&m,&T,&n) && (m || T || n)) {
        for(int i=1;i<=T;i++) {
            for(int j=1;j<=m;j++) scanf("%lf",&a[i][j]);
        }
        memset(x, 0, sizeof(x));
        ++kase;
        for(int i=1;i<=T;i++) {
            x[i][0][0] = 1;
            for(int j=1;j<=m;j++) {
                x[i][j][0] = x[i][j-1][0] * (1 - a[i][j]);
            }
            for(int j=1;j<=m;j++) {
                for(int k=1;k<=j;k++) {
                    x[i][j][k] = x[i][j-1][k-1] * a[i][j];
                    if(j-1 >= k) x[i][j][k] += x[i][j-1][k] * (1 - a[i][j]);
                }
            }
        }
        double ans = dp(1, 0);
        printf("%.3f\n",ans);
    }
    return 0;
}


你可能感兴趣的:(HDU,ACM-ICPC,概率DP)