NOIP 模擬題 天上掉餡餅

C 天上掉餡餅
文件名 輸入文件 輸出文件 時間限制 空間限制
bonus.pas/c/cpp bonus.in bonus.out 1s 128MB

題目描述
小 G 進入了一個神奇的世界,在這個世界,天上會掉下一些餡餅。今天,天上
會隨機掉下 k 個餡餅。
每次天上掉下餡餅, 小 G 可以選擇吃或者不吃(必須在下一個餡餅掉下來之前
作出選擇,並且現在決定不吃的話以後也不能吃) 。
餡餅有 n 種不同的餡,根據物理定律,天上掉下這 n 種餡餅的概率相同且相互
獨立。然而,每一種餡餅 i 都有一個前提餡餅集合 S i 。只有當 S i 中的餡餅都吃過
之後,才能吃第 i 種餡餅。比如說,韭菜餡餡餅的 S 中有白菜豬肉餡餅和鮮蝦餡餅,
那麼小 G 只有在吃過白菜豬肉餡餅和鮮蝦餡餅之後,才能吃韭菜餡的餡餅。
同時,每個餡餅還有一個美味值 P i 。今天一天小 G 的幸福度,等於小 G 吃到
的所有餡餅的美味值之和。注意,P i 可能是負數。
現在考慮,在採用最優策略的前提下,小 G 這一天期望的幸福度是多少?

輸入格式
第一行兩個正整數 k 和 n,表示餡餅的數量和種類。
以下 n 行,每行若干個數,描述一種餡餅。其中第一個數代表美味值,隨後的
整數表示該餡餅的前提餡餅,以 0 結尾。

輸出格式
輸出一個實數,保留 6 位小數,即在最優策略下期望的幸福度。

樣例輸入 1
1 2
1 0
2 0
樣例輸出 1
1.500000

數據範圍
對於 20% 的數據,所有的餡餅都沒有“前提餡餅”
對於 50% 的數據,1 ≤ k ≤ 10,1 ≤ n ≤ 10
對於 100% 的數據,1 ≤ k ≤ 100,1 ≤ n ≤ 15,美味度爲屬於 [−10^6 ,10^6 ] 的整

狀壓DP
對後續決策有影響的是什麼?
現在已經吃了哪些餡餅
令F[i][s]表示考慮前i次餡餅掉落事件,吃了s這個二進制狀態表示的餡餅,期望的美味值
對於每一次掉餡餅,枚舉掉下來的餡餅是誰
若s&a[j]==a[j](a[i]爲前提餡餅集合)
F[i][s] -> F[i+1][s|(1<<(j-1))]
注意要 /n
遞推的順序?
一個起始狀態,多個目標狀態,正推會導致無效狀態
反着推

其實是求得的最優解/它的概率,即maxn/n^k

因爲n^k不能取模,所以在dp時,每次都/n就可以了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int maxn=17;
double f[110][(1<<maxn)];
int k,n,a[110],v[110];
int main()
{
    freopen("bonus.in","r",stdin);
    freopen("bonus.out","w",stdout);
    scanf("%d%d",&k,&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&v[i]);
        while(1)
        {
            int x;scanf("%d",&x);
            if(!x) break;
            a[i]^=(1<<x-1);
        }
    }
    for(int i=k;i>=1;i--)
      for(int j=0;j<(1<<n);j++){
        for(int p=1;p<=n;p++)
          if((a[p]&j)==a[p])
             f[i][j]+=max(f[i+1][j],f[i+1][j|(1<<p-1)]+v[p]);
          else f[i][j]+=f[i+1][j];
      f[i][j]=f[i][j]/(double)n;    
    }
    printf("%.6lf",f[1][0]);
    return 0;
}
發佈了339 篇原創文章 · 獲贊 240 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章