1. 程式人生 > >2018.09.23 bzoj1076: [SCOI2008]獎勵關(期望+狀壓dp)

2018.09.23 bzoj1076: [SCOI2008]獎勵關(期望+狀壓dp)

傳送門 一道神奇的期望狀壓dp。 用f[i][j]f[i][j]表示目前在第i輪已選取物品狀態為j,從現在到第k輪能得到的最大貢獻。 如果我們從前向後推有可能會遇到不合法的情況。 所以我們從後向前推。 這時怎麼處理不合法的情況呢? 如果當前這個狀態不具備選擇k的條件。 那麼說明第i+1輪可能具備。 於是f[i][j]+=f[i+1][j]f[i][j]+=f[i+1][j] 否則當前具備選k的條件。 所以要麼當前輪不選,要麼選了從f[i+1][j(1<<(k1))]f[i+1][j|(1<<(k-1))]

轉移過來。 程式碼:

#include<bits/stdc++.h>
using namespace std;
double f[105][1<<16];
int K,n,w[16],ban[16];
int main(){
	scanf("%d%d",&K,&n);
	for(int i=1;i<=n;++i){
		scanf("%d",&w[i]);
		int tmp;
		while(scanf("%d",&tmp)&&tmp)ban[i]|=1<<
(tmp-1); } int up=1<<n; for(int i=K;i;--i){ for(int j=0;j<up;++j){ for(int k=1;k<=n;++k){ if((j&ban[k])==ban[k])f[i][j]+=max(f[i+1][j],f[i+1][j|(1<<(k-1))]+w[k]); else f[i][j]+=f[i+1][j]; } f[i][j]/=1.0*n; } } printf("%.6lf",f[1][0]); return 0; }