[SCOI2008]獎勵關
阿新 • • 發佈:2017-10-30
true etc eof dig [0 cnblogs amp sdi code f[i][j]+=max(f[i-1][j],f[i-1][j|(1<<k)]+p[k]);
如果不在j裏面,那麽是不合法狀態,吐不出來。
f[i][j]+=f[i-1][j];
最終答案即為f[k][0]。
題目大意:
你有k次獲取寶物的機會,每次會等概率的從1~n中選出一種寶物給你。
每種寶物都有一個依賴s,表示你只有先吃了s中的所有寶物才能吃當前寶物,如果S沒吃完,視作放棄吃當前寶物的機會。
每個寶物有一個價值p,求你獲取k個寶物以後的期望收益。
思路:
狀壓DP。
f[i][j]表示吃了i輪後,狀態為j的最大收益。
這樣轉移看起來很方便,但是遇到不合法狀態的時候就會很麻煩。
因此考慮把吃寶物的過程到過來,變成吐寶物。寶物i先於s[i]中所有寶物吐。
考慮吐了i輪,在狀態j下,吐出寶物k。
如果s[k]都在j裏面,那麽可以放心地吐。
如果不在j裏面,那麽是不合法狀態,吐不出來。
f[i][j]+=f[i-1][j];
最終答案即為f[k][0]。
1 #include<cstdio> 2 #include<cctype> 3 #include<cstring> 4 #include<algorithm> 5 inline int getint() { 6 register char ch; 7 register boolneg=false; 8 while(!isdigit(ch=getchar())) if(ch==‘-‘) neg=true;; 9 register int x=ch^‘0‘; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^‘0‘); 11 return neg?-x:x; 12 } 13 const int K=2,N=15; 14 int p[N],s[N]; 15 double f[K][1<<N]; 16 int main() { 17int k=getint(),n=getint(); 18 for(register int i=0;i<n;i++) { 19 p[i]=getint(); 20 for(register int x=getint();x;x=getint()) { 21 s[i]|=1<<(x-1); 22 } 23 } 24 for(register int i=1;i<=k;i++) { 25 memset(f[i&1],0,sizeof *f); 26 for(register int j=0;j<(1<<n);j++) { 27 for(register int k=0;k<n;k++) { 28 if((s[k]&j)==s[k]) { 29 f[i&1][j]+=std::max(f[!(i&1)][j],f[!(i&1)][j|(1<<k)]+p[k])/n; 30 } else { 31 f[i&1][j]+=f[!(i&1)][j]/n; 32 } 33 } 34 } 35 } 36 printf("%.6f\n",f[k&1][0]); 37 return 0; 38 }
[SCOI2008]獎勵關