Description
Solution
状压(dp) (+) 概率(dp)
看数据范围 (n leq 15),考虑状压。
我们把每一个宝物的前提宝物进行状态压缩。
设计 (dp) 状态:
(f[i][j]) 表示进行到第 (i) 轮,获得宝物状态为 (j) 时,能获得的最大收益。
不难发现,
当宝物 (k) 的前提宝物全部被选取时: (f[i][j] += max(f[i - 1][j], f[i - 1][j | (1 << (k - 1))]))
反之 (f[i][j] += f[i - 1][j])
但是这样写有一点小问题。
可能在第 (i) 轮时,无法选取到状态 (j)。
所以我们要倒着循环转移。
Code
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 110;
int m, n;
int a[N], sta[N];
double f[N][1 << 15];
int main(){
scanf("%d%d", &m, &n);
for(int i = 1; i <= n; i++){
int x;
scanf("%d", &a[i]);
while(scanf("%d", &x) && x)
sta[i] |= (1 << (x - 1));
}
for(int i = m; i >= 1; i--)
for(int j = 0; j < (1 << n); j++){
for(int k = 1; k <= n; k++){
if((j & sta[k]) == sta[k])
f[i][j] += max(f[i + 1][j], f[i + 1][j | (1 << (k - 1))] + a[k]);
else f[i][j] += f[i + 1][j];
}
f[i][j] /= n;
}
printf("%.6lf
", f[1][0]);
return 0;
}