codeforces 167B Wizards and Huge Prize (概率dp,类似背包)

题意:

给出n个比赛,每个比赛都有赢的概率pi,并且能得到一定的钱,但是钱需要背包装,比赛赢了分两个情况:一个是获得金币,一个是将背包扩容,如果值为-num表示得到num的金币,如果是正表示背包扩容。问至少赢了l局并且背包能装下的最大概率。

题解:

很明显的概率dp,类似于背包,和之前做的比起来简直简单爆了。两个决策一个取一个不去。

dp[i][j][k]表示前i个比赛赢了j个比赛还剩的容量k,所得的最大概率。注意这题是有顺序的,比如我先打最后一个等有足够的背包了在回去打是可以的。那么怎么才能让他无序?我们可以将背包右移200个的单位。这样200以下的就代表负值的背包,这样就不用考虑顺序,前面的情况会转移到后面处理。最后只要去背包在200到400之间的dp就好了(因为最后的背包剩余容量肯定要是大于0的)


#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
const int oo=0x3f3f3f3f;
const ll OO=1LL<<61;
const int Mod=1000000007;
const int maxn=200+5;
double dp[maxn][maxn][maxn<<1],p[maxn];
int v[maxn];

int main()
{
    int n,l,w,allw;
    scanf("%d %d %d",&n,&l,&w);
    for(int i=1;i<=n;i++)
        scanf("%lf",&p[i]),p[i]/=100;
    for(int i=1;i<=n;i++)
        scanf("%d",&v[i]);
    memset(dp,0,sizeof dp);
    dp[0][0][w+200]=1.0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<=i;j++)
        {
            for(int k=0;k<=400;k++)
            {
                int t=min(400,k+v[i+1]);
                dp[i+1][j][k]+=dp[i][j][k]*(1-p[i+1]);
                if(t>=0)
                    dp[i+1][j+1][t]+=dp[i][j][k]*p[i+1];
            }
        }
    }
    double ans=0.0;
    for(int j=l;j<=n;j++)
        for(int k=200;k<=400;k++)///选取条件必须背包要大于0才行
            ans+=dp[n][j][k];
    printf("%.12lf\n",ans);
    return 0;
}







你可能感兴趣的:(codeforces 167B Wizards and Huge Prize (概率dp,类似背包))