1. 程式人生 > >P2473 [SCOI2008]獎勵關

P2473 [SCOI2008]獎勵關

-html 機會 new 平均情況 std scan sin htm 種類

P2473 [SCOI2008]獎勵關

鏈接:https://www.luogu.org/problemnew/show/P2473

題目背景

08四川NOI省選

題目描述

你正在玩你最喜歡的電子遊戲,並且剛剛進入一個獎勵關。在這個獎勵關裏,系統將依次隨機拋出k次寶物,每次你都可以選擇吃或者不吃(必須在拋出下一個寶物之前做出選擇,且現在決定不吃的寶物以後也不能再吃)。

寶物一共有n種,系統每次拋出這n種寶物的概率都相同且相互獨立。也就是說,即使前k-1 次系統都拋出寶物1(這種情況是有可能出現的,盡管概率非常小),第k次拋出各個寶物的概率依然均為1/n。

獲取第 i 種寶物將得到Pi分,但並不是每種寶物都是可以隨意獲取的。第i種寶物有一個前提寶物集合Si。只有當Si中所有寶物都至少吃過一次,才能吃第i 種寶物(如果系統拋出了一個目前不能吃的寶物,相當於白白的損失了一次機會)。註意,Pi 可以是負數,但如果它是很多高分寶物的前提,損失短期利益而吃掉這個負分寶物將獲得更大的長期利益。

假設你采取最優策略,平均情況你一共能在獎勵關得到多少分值?

輸入輸出格式

輸入格式:

第一行為兩個正整數k 和n,即寶物的數量和種類。以下n行分別描述一種

寶物,其中第一個整數代表分值,隨後的整數依次代表該寶物的各個前提寶物(各

寶物編號為1到n),以0結尾。

輸出格式:

輸出一個實數,保留六位小數,即在最優策略下平均情況的得分。

題解:dp[i][s]表示還剩i輪已經去了的狀態,

1、如果 SS 包含的狀態滿足取第 kk 種寶物的條件,則可以取或不取。不取則為 f[i+1][S]f[i+1][S] ,取則為 f[i+1][S|(1<<k-1)]+P_kf[i+1][S(1<<k?1)]+Pk?

所以此時 f[i][S]+=max(f[i+1][S],f[i+1][S|(1<<k-1)]+P_k)f[i][S]+=max(f[i+1][S],f[i+1][S(1<<k?1)]+Pk?) 。

2、如果 SS 包含的狀態不滿足取第 kk 種寶物的條件,則不能取,即 f[i][S]+=f[i+1][S]f[i][S]+=f[i+1][S] 。

#include <bits/stdc++.h>
using namespace std;


const int maxn = 4e4;
int w[20],sta[maxn];
double dp[105][maxn];
int main(){ int n,k; scanf("%d%d",&k,&n); for(int i = 1; i <= n; i++){ scanf("%d",&w[i]); int pre; while(scanf("%d",&pre) == 1){ if(!pre)break; sta[i] |= (1<<(pre-1)); } } for(int i = k; i >= 1; i--) for(int s = 0; s <= (1<<n)-1; s++){ for(int j = 1; j <= n; j++){ if(sta[j] == (sta[j] & s))//能不能選j dp[i][s] += max(dp[i+1][s], dp[i+1][s|(1<<(j-1))]+w[j]); else dp[i][s] += dp[i+1][s]; } dp[i][s] /= n; } printf("%.6lf",dp[1][0]); }

輸入輸出樣例

輸入樣例#1: 復制
1 2
1 0
2 0
輸出樣例#1: 復制
1.500000
輸入樣例#2: 復制
6 6
12 2 3 4 5 0
15 5 0
-2 2 4 5 0
-11 2 5 0
5 0
1 2 4 5 0
輸出樣例#2: 復制
10.023470

說明

1 <= k <= 100, 1 <= n <= 15,分值為[-106,106]內的整數。

題解:

P2473 [SCOI2008]獎勵關