BZOJ 1076 [SCOI2008]奖励关

显然要记f[i][s]表示做到第k次,此时已有的物品集合为S的期望得分。下文前者指时间靠前的状态,后者指时间靠后的状态。

如果正向DP,即f[i-1] -> f[i],会出问题。因为这样意味着第i次的决策可以根据第i次出现的不同物品来改变第i-1次的决策。即我们枚举第i次出现的物品,对i-1的不同s取max,就会后者决定前者。

应当反向DP,即f[i+1] -> f[i]。也就是前者根据后者不同情况的不同答案来决定自己的后继,是前者决定后者。答案就是f[1][0]。

#include<cstdio>
#include<algorithm>
#define N 16
#define K 105
using namespace std;
namespace runzhe2000
{
    const double INF = 1e9;
    int s[N], p[N];
    double f[K][1<<N];
    void main()
    {
        int k, n; scanf("%d%d",&k,&n);
        for(int i = 1; i <= n; i++)
        {
            scanf("%d",&p[i]);

            while(1)
            {
                char ch = getchar(); int r = 0;
                for(; ch < '0' || ch > '9'; ch = getchar());
                while(ch >= '0' && ch <= '9') r = r * 10 + ch - '0', ch = getchar();
                if(r) s[i] |= 1<<(r-1);
                else break;
            }
        }
        int sta = 1<<n;
        for(int i = k; i; i--)
        {
            for(int j = 0; j < sta; j++)
            {
                for(int k = 1; k <= n; k++)
                {
                    if((j&s[k]) == s[k])
                        f[i][j] += (1.0/n) * max( f[i+1][j], f[i+1][ j | (1<<(k-1)) ] + p[k] );
                    else f[i][j] += (1.0/n) * f[i+1][j];
                }
            }
        }
        printf("%.6lf\n",f[1][0]);
    }
}
int main()
{
    runzhe2000::main();
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值