2018.09.23 bzoj1076: [SCOI2008]奖励关(期望+状压dp)

版权声明:随意转载哦......但还是请注明出处吧: https://blog.csdn.net/dreaming__ldx/article/details/82824552

传送门
一道神奇的期望状压dp。
f [ i ] [ j ] f[i][j] 表示目前在第i轮已选取物品状态为j,从现在到第k轮能得到的最大贡献。
如果我们从前向后推有可能会遇到不合法的情况。
所以我们从后向前推。
这时怎么处理不合法的情况呢?
如果当前这个状态不具备选择k的条件。
那么说明第i+1轮可能具备。
于是 f [ i ] [ j ] + = f [ i + 1 ] [ j ] f[i][j]+=f[i+1][j]
否则当前具备选k的条件。
所以要么当前轮不选,要么选了从 f [ i + 1 ] [ j ( 1 < < ( k 1 ) ) ] f[i+1][j|(1<<(k-1))] 转移过来。
代码:

#include<bits/stdc++.h>
using namespace std;
double f[105][1<<16];
int K,n,w[16],ban[16];
int main(){
	scanf("%d%d",&K,&n);
	for(int i=1;i<=n;++i){
		scanf("%d",&w[i]);
		int tmp;
		while(scanf("%d",&tmp)&&tmp)ban[i]|=1<<(tmp-1);
	}
	int up=1<<n;
	for(int i=K;i;--i){
		for(int j=0;j<up;++j){
			for(int k=1;k<=n;++k){
				if((j&ban[k])==ban[k])f[i][j]+=max(f[i+1][j],f[i+1][j|(1<<(k-1))]+w[k]);
				else f[i][j]+=f[i+1][j];
			}
			f[i][j]/=1.0*n;
		}
	}
	printf("%.6lf",f[1][0]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/dreaming__ldx/article/details/82824552