[SCOI2008]奖励关

题目

思路

显然状态压缩DP,先设\(f_{i,S}\)表示到了第\(i\)轮,状态为\(S\)时的最大价值,用刷表法正推求解;

然后就发现有些问题,因为就连题目都举了个栗子说明你当前的决策需要考虑未来的情况,这样会有后效性

所以需要逆推求解,设\(f_{i,S}\)表示还剩\(i\)论,状态为\(S\)时的最大价值,每次决策选或者不选,用刷表法逆推求解

Code

#include<bits/stdc++.h>
#define N 105
#define M 16 
using namespace std;
int k,n,rf[M],p[M];
double f[N][1<<M];//当前还有i次机会,当前状态为j的未来期望价值 

template <class T>
void read(T &x)
{
	char c;int sign=1;
	while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
	while((c=getchar())>='0'&&c<='9') x=x*10+c-48; x*=sign;
}

int main()
{
	read(k);read(n);
	for(int i=1;i<=n;++i)
	{
		read(p[i]);
		while(1)
		{
			int x; read(x); 
			if(!x) break;
			rf[i]|=(1<<(x-1));
		}
	}
	for(int i=0;i<k;++i)
	  for(int j=0,t=(1<<n);j<t;++j)//i+1层为j状态 
		for(int q=1;q<=n;++q)//选q 
		{
			if((rf[q]&j)!=rf[q]) f[i+1][j]+=f[i][j]/n;
			else f[i+1][j] += max( (p[q] + f[i][j|(1<<(q-1))]) /n , f[i][j] /n );
		}
	printf("%.6lf\n",f[k][0]);
	return 0;
}
posted @ 2019-10-17 14:17  擅长平地摔的艾拉酱  阅读(76)  评论(0编辑  收藏  举报
/*取消选中*/