洛谷 P2473 [SCOI2008] 奖励关

Description

P2473 [SCOI2008] 奖励关

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

End

posted @ 2021-08-19 18:11  xixike  阅读(26)  评论(0编辑  收藏  举报