BZOJ1076: [SCOI2008]獎勵關【狀壓DP+指望DP】

Description

  你正在玩你最喜歡的電子遊戲,而且剛剛進入一個獎勵關。在這個獎勵關裏,系統將依次隨機拋出k次寶物,
每次你均可以選擇吃或者不吃(必須在拋出下一個寶物以前作出選擇,且如今決定不吃的寶物之後也不能再吃)。
寶物一共有n種,系統每次拋出這n種寶物的機率都相同且相互獨立。也就是說,即便前k-1次系統都拋出寶物1(
這種狀況是有可能出現的,儘管機率很是小),第k次拋出各個寶物的機率依然均爲1/n。 獲取第i種寶物將獲得Pi
分,但並非每種寶物都是能夠隨意獲取的。第i種寶物有一個前提寶物集合Si。只有當Si中全部寶物都至少吃過
一次,才能吃第i種寶物(若是系統拋出了一個目前不能吃的寶物,至關於白白的損失了一次機會)。注意,Pi可
以是負數,但若是它是不少高分寶物的前提,損失短時間利益而吃掉這個負分寶物將得到更大的長期利益。 假設你
採起最優策略,平均狀況你一共能在獎勵關獲得多少分值?c++

Input

  第一行爲兩個正整數k和n,即寶物的數量和種類。如下n行分別描述一種寶物,其中第一個整數表明分值,隨
後的整數依次表明該寶物的各個前提寶物(各寶物編號爲1到n),以0結尾。spa

Output

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

Sample Input

1 2
1 0
2 0遊戲

Sample Output

1.500000ip

HINT

【數據規模】input

1<=k<=100,1<=n<=15,分值爲\([-10^6,10^6]\)內的整數。it


思路

正着考慮是很差計算的io

因此就能夠反着考慮class

而後每次枚舉第i次獎勵以前的狀態和當前獎勵的物品而後選取最優值就能夠了數據

每次算的時候須要除以方案數n


#include<bits/stdc++.h>

using namespace std;

const int N = (1 << 15) + 10;
const int K = 110;

int pre[N], n, k;
double p[N], dp[K][N];

int main() {
  scanf("%d %d", &k, &n);
  for (int i = 1; i <= n; i++) {
    scanf("%lf", &p[i]);
    int u; scanf("%d", &u);
    while (u) {
      pre[i] |= 1 << (u - 1);
      scanf("%d", &u);
    }
  }
  int up = 1 << n;
  for (int i = k; i >= 1; i--) {
    for (int s = 0; s < up; s++) {
      for (int j = 1; j <= n; j++) {
        if ((s & pre[j]) == pre[j]) {
          dp[i][s] += max(dp[i + 1][s], dp[i + 1][s | (1 << (j - 1))] + p[j]); 
        } else {
          dp[i][s] += dp[i + 1][s];
        }
      }
      dp[i][s] /= (double) n;
    }
  }
  printf("%.6lf", dp[1][0]);
  return 0;
}
相關文章
相關標籤/搜索