[SCOI2008]奖励关

题面在这里

题意

不好描述.....大家还是看luogu上的吧(资磁洛谷!)

sol

(n<=15)的良心数据肯定是状压啦
只是设状态的时候有点头疼
首先思考我们在无法预知之后宝物的情况下如何求解
对于第i个宝物,如果我们没有满足吃掉的条件的话就只能放弃(可惜...)
如果我们能吃掉,那么就需要观察吃掉它和不吃掉它的期望哪个更高,从更优的期望中进行决策
所以这样的思路让我们必须倒着DP
(f[i][x])表示当前已经吃掉的宝物状态为x的时候,迎接第i个宝物,在最优决策下所能得到的期望
之后按照上面的思路转移即可

代码

#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define mp make_pair
#define pb push_back
#define RG register
#define il inline
using namespace std;
const int mod=1e9+7;
const int N=16;
const double eps=1e-10;
typedef unsigned long long ull;
typedef vector<int>VI;
typedef long long ll;
typedef double dd;
il ll read(){
	RG ll data=0,w=1;RG char ch=getchar();
	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
	if(ch=='-')w=-1,ch=getchar();
	while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
	return data*w;
}

dd f[105][65537];
int k,n,p[N],need[N][N],g[65537];
bool check[65537];

il bool pd(int x){//判断一个状态是否为合法状态
	for(RG int i=1;i<=n;i++)
		if((x&(1<<(i-1)))==(1<<(i-1)))
			for(RG int j=1;j<=need[i][0];j++)
				if((x&(1<<(need[i][j]-1)))!=(1<<(need[i][j]-1)))
					return 0;
	return 1;
}

il void DP(){		
	for(RG int i=k;i;i--)
		for(RG int j=1,x=g[j];j<=g[0];j++,x=g[j]){
			for(RG int a=1;a<=n;a++){
				if(check[x|(1<<(a-1))]&&f[i+1][x|(1<<(a-1))]+p[a]>f[i+1][x]){
					//在选择合法的情况下,吃掉更优
					f[i][x]+=f[i+1][x|(1<<(a-1))]+p[a];
				}
				else f[i][x]+=f[i+1][x];//不能吃或不吃更优
			}
			f[i][x]/=n;
		}
}

int main()
{
	k=read();n=read();
	for(RG int i=1,x;i<=n;i++){
		p[i]=read();
		while(x=read())need[i][++need[i][0]]=x;
	}

	for(RG int i=0;i<(1<<n);i++)
		if(check[i]=pd(i))g[++g[0]]=i;
    //预处理出所有合法状态

	DP();
	
	printf("%.6lf
",f[1][0]);
	return 0;
}

友链

SYCdalao的题解见这里

原文地址:https://www.cnblogs.com/cjfdf/p/8405357.html