[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;
}