Luogu P2473 [SCOI2008]獎勵關

比較噁心的機率(指望)+狀壓DP,想正推2H的我瑟瑟發抖git

因爲數據範圍不大,所以咱們能夠直接狀壓每一個寶物取或不取的狀況,設\(f_{i,j}\)表示前\(i\)輪且寶物是否取過的狀態爲\(j\)時的方案總數,可是咱們發現這樣可能會致使一些不合法的狀態也獲得轉移,所以咱們考慮倒推spa

\(f_{i,j}\)表示表示在第\(1\)輪到第\(i-1\)輪內寶物是否取過的狀態爲\(j\),第\(i\)輪到第\(k\)輪的最大指望得分,那麼這樣就能夠經過倒推動行轉移了。code

具體轉移的時候咱們枚舉全部的寶物限制,那麼轉移就很明顯了it

不過因爲這裏要求的是指望值,而每一次須要除以\(n\),最後的\(f_{1,0}\)即爲答案io

CODEclass

#include<cstdio>
#include<cctype>
using namespace std;
typedef double DB;
const int N=16,INF=-1e9;
int n,p[N],m,s[N],x,tot;
DB f[105][(1<<N)+5];
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{   
    x=0; char ch; int flag=1; while (!isdigit(ch=tc())) flag=ch^'-'?1:-1;
    while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); x*=flag;
}
inline int calc(int x)
{
    int res=0; while (x) res+=x&1,x>>=1; return res;
}
inline DB max(DB a,DB b)
{
    return a>b?a:b;
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    register int i,j,k; read(m); read(n); tot=(1<<n)-1;
    for (i=0;i<n;++i)
    {
        read(p[i]); read(x);
        while (x) s[i]|=(1<<x-1),read(x);
    }
    for (i=m;i>=1;--i)
    for (j=0;j<=tot;++j)
    {
        for (k=0;k<n;++k)
        if ((s[k]&j)==s[k]) f[i][j]+=max(f[i+1][j],f[i+1][j|(1<<k)]+p[k]); else f[i][j]+=f[i+1][j];
        f[i][j]=(DB)f[i][j]/n;
    }
    return printf("%.6lf",f[1][0]),0;
}
相關文章
相關標籤/搜索