牛客网 Wannafly挑战赛8 C-小C打比赛 (状压DP)
小C现在要参加一场wannafly挑战赛,一场挑战赛一共有n道题,一共有m分钟。
对于第i道题,小C解决它需要恰好j分钟的概率是pi,j。
小C每次会选择某一道没做完的题,然后把它解决(不能中途放弃),之后再决策下一道要做的题是哪道。
求小C在最优策略下,期望能做出几道题。
对于第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; }