bzoj1076: [SCOI2008]獎勵關 狀壓dp
阿新 • • 發佈:2018-10-06
() rec ble 電子遊戲 bzoj1076 現在 得到 ios 負數
以是負數,但如果它是很多高分寶物的前提,損失短期利益而吃掉這個負分寶物將獲得更大的長期利益。 假設你
采取最優策略,平均情況你一共能在獎勵關得到多少分值?
Description
你正在玩你最喜歡的電子遊戲,並且剛剛進入一個獎勵關。在這個獎勵關裏,系統將依次隨機拋出k次寶物,
每次你都可以選擇吃或者不吃(必須在拋出下一個寶物之前做出選擇,且現在決定不吃的寶物以後也不能再吃)。
寶物一共有n種,系統每次拋出這n種寶物的概率都相同且相互獨立。也就是說,即使前k-1次系統都拋出寶物1(
這種情況是有可能出現的,盡管概率非常小),第k次拋出各個寶物的概率依然均為1/n。 獲取第i種寶物將得到Pi
分,但並不是每種寶物都是可以隨意獲取的。第i種寶物有一個前提寶物集合Si。只有當Si中所有寶物都至少吃過
一次,才能吃第i種寶物(如果系統拋出了一個目前不能吃的寶物,相當於白白的損失了一次機會)。註意,Pi可
采取最優策略,平均情況你一共能在獎勵關得到多少分值?
Input
第一行為兩個正整數k和n,即寶物的數量和種類。以下n行分別描述一種寶物,其中第一個整數代表分值,隨
後的整數依次代表該寶物的各個前提寶物(各寶物編號為1到n),以0結尾。
Output
輸出一個實數,保留六位小數,即在最優策略下平均情況的得分。
題解
首先這題要倒著掃(正著掃我寫掛了,理論上應該沒問題),倒著由合法情況推至下一個合法情況,避免掃不合法的。
很明顯狀壓n種寶箱,1代表打開了,0代表沒打開。
考慮第i次能不能從第i+1次打開第p個寶箱轉移過來,可以就由打開第p個寶箱和不打開寶箱中更優的轉移,否則直接由不打開寶箱轉移。
代碼
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include <iomanip> using namespace std; const int maxn=(1<<15)+10; int K,n; int w[20]; int nxt[20]; int ch[20][20]; double f[110][maxn]; double max(double a,double b){return a>b?a:b;} int main(){ cin>>K>>n; for(int i=1;i<=n;i++){ cin>>w[i]; int x;cin>>x; while(x){ ch[i][x]=1; cin>>x; } } for(int i=1;i<=n;i++) for(int j=n;j>=1;j--) nxt[i]=(nxt[i]<<1)+ch[i][j]; for(int i=K;i>=1;i--) for(int j=0;j<(1<<n);j++){ for(int k=1;k<=n;k++){ if((nxt[k]&j)==nxt[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]/=n; } cout.unsetf(ios::fixed); cout<<fixed<<setprecision(6)<<f[1][0]<<endl; return 0; }
bzoj1076: [SCOI2008]獎勵關 狀壓dp