牛客网 Wannafly挑战赛8 C-小C打比赛 (状压DP)

小C现在要参加一场wannafly挑战赛,一场挑战赛一共有n道题,一共有m分钟。
对于第i道题,小C解决它需要恰好j分钟的概率是pi,j
小C每次会选择某一道没做完的题,然后把它解决(不能中途放弃),之后再决策下一道要做的题是哪道。
求小C在最优策略下,期望能做出几道题。

输入描述:

第一行两个正整数n,m
接下来一共n行,每行有m个小数,第i行的第j个小数表示p

i,j

(这里假设不存在0分钟A题的dalao)。

输出描述:

输出一个小数,表示期望能做出几道题,保留小数点后五位。
示例1

输入

2 5
0.2 0.2 0.2 0.2 0.2
0 0.25 0.25 0.25 0.25

输出

1.30000

备注:

1≤ n≤ 6,1≤ m≤ 180
每道题的概率和为1(每道题只要时间够一定能做出来)
输入最多四位小数

分析:最后期望做出的题数= 做出1、2、3....n的概率乘上对应的题数的结果的累加
根据题目的范围,暴搜会超时,而n又比较小,所以考虑状压DP
可以用dp[i][j]来表示 状态为i,时间为j的时候的期望
代码如下:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
double p[10][200];
double dp[1<<6+5][200];
int main()
{
    int n,m;
     memset(p,0,sizeof(p));
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
     for(int j=1;j<=m;j++)
        scanf("%lf",&p[i][j]);
     memset(dp,0,sizeof(dp));
     for(int i=1;i<(1<<n);i++)
        for(int j=1;j<=m;j++)
           for(int k=0;k<n;k++)
           {
              if((i&(1<<k))==0)continue;  
              double tmp=0;
              for(int r=1;r<=j;r++)tmp+= (1+dp[i^(1<<k)][j-r])*p[k][r]; 
              dp[i][j]=max(dp[i][j],tmp);
           }
        printf("%.5f\n",dp[(1<<n)-1][m]);

    return 0;
}

 




posted @ 2018-01-20 17:18  hinata_hajime  阅读(211)  评论(0编辑  收藏  举报