洛谷 P2473 [SCOI2008]奖励关(状压dp+期望)

题面

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
", f[1][0]);
	return 0;
}

原文地址:https://www.cnblogs.com/zzy2005/p/10551495.html