题目大意
每件物品等概率出现,有条件选择,求最优策略下期望概率。
Solution
首先,看完题目和数据范围,可以知道这是一个期望DP。我一开始从前往后推,然后发现怎么都推不出来,卡了半天……TAT。
原因在于,后面可能的状态会影响前面的选择,每一次的选择都跟后面可能的状态和前面的状态有关。那么如果倒着推,对于一定的状态来说,后面的最优策略已经确定,只要枚举前面所有可能的状态,判断每个后继状态最优的答案。这样,虽然有一部分计算是冗余的(即不可能出现),但在计算过程中只会把需要的部分加入答案。
#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<string>
#include<cstdio>
#include<vector>
#include<bitset>
#include<iomanip>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rep(i,a,b) for (int i=a; i<=b; i++)
#define per(i,a,b) for (int i=a; i>=b; i--)
using namespace std;
typedef long long LL;
inline int read() {
int x=0,f=1; char ch=getchar();
while (!(ch>='0'&&ch<='9')) {if (ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9') {x=x*10+(ch-'0'); ch=getchar();}
return x*f;
}
const int N = 105;
const int M = 1<<15;
const int C = 15;
int K,n;
int val[C],need[C];
double dp[N][M],P;
int main() {
#ifndef ONLINE_JUDGE
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
#endif
K=read(),n=read();
rep(i,0,n-1) {
val[i]=read(); int sta=0;
while (true) {
int x=read(); x--;
if (x==-1) break;
sta|=(1<<x);
}
need[i]=sta;
}
P=1.0/n;
per(i,K-1,0) {
rep(j,0,(1<<n)-1) {
rep(k,0,n-1) {
if ((need[k]&j)==need[k]) dp[i][j]+=max(dp[i+1][j|(1<<k)]+val[k],dp[i+1][j])*P;
else dp[i][j]+=dp[i+1][j]*P;
}
}
}
printf("%.6lf\n",dp[0][0]);
return 0;
}