分析
首先宝物种类比较少,可以想到状压dp,但是终态非常多,可以尝试转化把初态和终态调换,设 d p [ i ] [ s ] dp[i][s] dp[i][s]表示前 i − 1 i-1 i−1轮取了集合 s s s的期望,那么 d p [ i ] [ s ] = ∑ k = 1 n max { d p [ i + 1 ] [ s ] , d p [ i + 1 ] [ s ∣ 2 k − 1 ] + w [ k ] ( 若 s 满 足 要 求 ) } / n dp[i][s]=\sum_{k=1}^n\max\{dp[i+1][s],dp[i+1][s|2^{k-1}]+w[k](若s满足要求)\}/n dp[i][s]=∑k=1nmax{dp[i+1][s],dp[i+1][s∣2k−1]+w[k](若s满足要求)}/n,其实貌似没什么难度
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
double dp[2][40001];
int n,m,a[17],lim[17];
inline signed iut(){
rr int ans=0,f=1; rr char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans*f;
}
inline double max(double &a,double b){return a>b?a:b;}
signed main()
{
m=iut(); n=iut();
for (rr int i=1;i<=n;++i){
a[i]=iut(); rr int x;
while (x=iut()) lim[i]|=1<<(x-1);
}
for (rr int i=m;i;--i)
for (rr int j=0;j<(1<<n);++j){
dp[i&1][j]=0;
for (rr int k=1;k<=n;++k)
if ((j&lim[k])==lim[k])
dp[i&1][j]+=max(dp[(i&1)^1][j],dp[(i&1)^1][j|(1<<(k-1))]+a[k]);
else dp[i&1][j]+=dp[(i&1)^1][j];
dp[i&1][j]/=n;
}
return !printf("%.6lf",dp[1][0]);
}