很容易想到状压,f[i][s]表示前i个选择的箱子集合为s的最大期望
果断wa了,因为有一些不合法的状态,譬如f[1][1111001]这样的状态
这样的状态不好排除,所以改用倒推
用f[i][s]表示i-1的选择集合为s的,i到k的最大期望
转移时枚举i处的选择,如果可以选该箱子,则为f[i+1][s|(1<<j)]
如果不选则为f[i+1][s]判断一下可行性然后取max就好了
# include<iostream> # include<cstdio> # include<algorithm> # include<cmath> # include<cstring> using namespace std; const int mn = 105; double f[mn][1<<15]; int n,k,val[mn],sit[mn]; int main() { scanf("%d%d",&k,&n); for(int i=1;i<=n;i++) { int t; scanf("%d%d",&val[i],&t); while(t) { sit[i]+=(1<<(t-1)); scanf("%d",&t); } } for(int i=k;i>=1;i--) { for(int j=0;j<(1<<n);j++) { for(int s=1;s<=n;s++) if((sit[s] & j) == sit[s]) f[i][j]+=max(f[i+1][j],f[i+1][j | (1<<(s-1))]+val[s]); else f[i][j]+=f[i+1][j]; f[i][j]=f[i][j]/(1.0*n); } } printf("%.6lf",f[1][0]); return 0; }