1. 程式人生 > >洛谷 P2473 [SCOI2008]獎勵關(狀壓dp+期望)

洛谷 P2473 [SCOI2008]獎勵關(狀壓dp+期望)

== sco [1] std \n max 應該 tchar amp

題面

luogu

題解

\(n \leq 15\)

狀壓

\(f[i][S]\)表示第\(i\)輪,吃過的集合為\(S\)

正著轉移好像有點復雜

考慮逆推轉移(正著轉移應該也行)

\(f[i][S]\)表示\([1,i-1]\)輪,吃過的集合為\(S\),第\(i\)輪到第\(k\)輪最大期望得分

Code

#include<bits/stdc++.h>

#define LL long long
#define RG register

const int N = 16;

using namespace std;
template<class T> inline void read(T &x) {
    x = 0; RG char c = getchar(); bool f = 0;
    while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1;
    while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar();
    x = f ? -x : x;
    return ;
}
template<class T> inline void write(T x) {
    if (!x) {putchar(48);return ;}
    if (x < 0) x = -x, putchar('-');
    int len = -1, z[20]; while (x > 0) z[++len] = x%10, x /= 10;
    for (RG int i = len; i >= 0; i--) putchar(z[i]+48);return ;
}
int k, n, need[N], w[N];
double f[110][1<<N];

int main() {
    read(k), read(n);
    for (int i = 0, x; i < n; i++) {
        read(w[i]);
        while (1) {read(x); if (!x) break; x--;need[i] |= (1 << x);}
    }
    int limit = 1 << n;
    for (int i = k; i; i--)
        for (int S = 0; S < limit; S++) {
            for (int j = 0; j < n; j++)
                if ((need[j] & S) == need[j])
                    f[i][S] += max(f[i + 1][S | (1 << j)] + w[j], f[i + 1][S]);
                else f[i][S] += f[i + 1][S];
            f[i][S] /= n;
        }
    printf("%lf\n", f[1][0]);
    return 0;
}

?

洛谷 P2473 [SCOI2008]獎勵關(狀壓dp+期望)