考虑 $DP$
容易想到设 $f[i][S]$ 表示考虑到第 $i$ 个物品,当前拥有物品集合为 $S$ 时最优策略下的期望得分
但是这样不能保证是最优策略,不知道后面的结果
换种状态,设 $f[i][S]$ 表示已经从 $i+2$ 考虑到最后一个物品,现在考虑第 $i+1$ 个,且从 $1$ 到 $i$ 的物品状态为 $S$ 的期望得分
设总物品数为 $m$ ,那么枚举所有物品 $k$
如果 $k$ 可以取,$f[i][S]+=max(f[i+1][S|(1<<k-1)]+val[k],f[i+1][S])/m$
如果不能取,$f[i][S]+=f[i+1][S]/m$
然后记忆化 $dfs$
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> 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<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=107,M=(1<<16)+1; int n,m,val[N],p[N]; double f[N][M],ans; bool vis[N][M]; double dfs(int i,int j) { if(i==n) return 0; if(vis[i][j]) return f[i][j]; for(int k=1;k<=m;k++) { if( (j&p[k])!=p[k] ) f[i][j]+=dfs(i+1,j)/m; else f[i][j]+=max(dfs(i+1,j|(1<<k-1))+val[k] , dfs(i+1,j))/m; } vis[i][j]=1; return f[i][j]; } int main() { int a; n=read(),m=read(); for(int i=1;i<=m;i++) { val[i]=read(); while(a=read()) p[i]|=(1<<a-1); } printf("%.6lf",dfs(0,0)); return 0; }