题目:https://www.luogu.org/problemnew/show/P2473
因为可不可选此物与之前选过什么物品有关,所以状态可以记录成前面已经选过什么物品。
因为选不选此物与它带来的贡献有关,而它的情况又会影响后面,所以值倒着推。
自己混乱的地方是状态,原来只需:本次此物是否是1无关,从它转移过来的那个状态此物必须是1,所以 | 一个就行!
因为是概率,所以各处/n,可以合并成算完后再/n。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=15; int n,m,list[N+5]; double dp[2][(1<<N)+5],c[N+5]; int main() { scanf("%d%d",&m,&n);int x,lm=(1<<n); for(int i=1;i<=n;i++) { scanf("%lf",&c[i]); while(1) { scanf("%d",&x);if(!x)break; list[i]|=(1<<(x-1)); } } for(int i=m;i;i--) { for(int j=0;j<lm;j++) { for(int k=1;k<=n;k++) { if((j&list[k])==list[k]) dp[1][j]+=max(dp[0][j|(1<<(k-1))]+c[k],dp[0][j]); else { dp[1][j]+=dp[0][j]; } } dp[1][j]/=n; } memcpy(dp[0],dp[1],sizeof dp[1]); memset(dp[1],0.0,sizeof dp[1]); } printf("%.6lf",dp[0][0]); return 0; }