[SCOI2008]奖励关

Description

BZOJ1076

Luogu2473

Solution

状压DP,倒着来,(f[i][S])表示前(i-1)个选了(S)(i)(k)的最大收益。

Code

const int N = 20;
const int MXS = (1 << 17);

int pre[N], k, n, a[N];
double F[110][MXS];

void main() {
    k = read(), n = read();
    for (int i = 1; i <= n; ++i) {
        a[i] = read();
        int x;
        while ((x = read()) != 0) pre[i] |= (1 << x);
    }
    for (int i = k; i; --i) {
        for (int S = 0; S < MXS; ++S) {
            for (int j = 1; j <= n; ++j)
                if ((S & pre[j]) == pre[j]) {
                    F[i][S] +=
                        std::max(F[i + 1][S | (1 << j)] + a[j], F[i + 1][S]);
                } else
                    F[i][S] += F[i + 1][S];
            F[i][S] /= n;
        }
    }
    printf("%.6lf
", F[1][0]);
}
原文地址:https://www.cnblogs.com/wyxwyx/p/bzoj1076.html