洛谷P2473 [SCOI2008]奖励关题解

本文介绍了如何利用状压DP解决SCOI2008奖励关的问题。由于数据范围限制,考虑使用状态转移。状态定义为fi,S表示前i-1个宝物在状态S下的第i到第k轮最大期望得分。通过枚举当前物品j,分析取与不取两种情况,并进行转移。最终答案为f1,0,整个过程需要除以n求期望。" 116330264,9288417,Python函数深入解析,"['Python', '编程语言', '函数定义', '参数传递']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

分析:

看到数据范围 n < = 15 n <= 15 n<=15 就很容易想到状压DP:用 f i , S f_{i,S} fi,S表示前 i i i个宝物在是否取过的状态为S的情况下的最大期望得分。

但仔细一想会发现前面的选择会影响到后面的每个宝物是否能取,即不满足DP的无后效性原则。所以,我们将状态改为用 f i , S f_{i,S} fi,S表示前 i − 1 i - 1 i1个宝物在是否取过的状态为S的情况下第 i i i到第 k k k轮的最大期望得分。这样就可以倒序枚举第一维,满足无后效性原则。

转移时对于每一个 f i , S f_{i,S} fi,S,枚举当前物品 j j j,显然有两种情况(我们用 s i s_i si表示宝物 i i i的前提宝物集合, a i a_i ai表示宝物 i i i的权值):

1、当前取不到 j j j,即 S   &   s j ≠ s j S\,\&\,s_j \not= s_j S&sj=sj时:

只能由不取转移,即:
f i , S = f i , S + f i + 1 , S f_{i,S} = f_{i,S} + {f_{i + 1,S}} fi,S=fi,S+fi+1,S

2、当前可以取 j j j,即 S   &   s j = s j S\,\&\,s_j = s_j S&sj=sj时:

选择取和不取中的最大值转移:
f i , S = f i , S + m a x ( f i + 1 , S , f i + 1 , S   ∣   2 j − 1 + a j ) f_{i,S} = f_{i,S} + {max(f_{i + 1,S},f_{i + 1,S \, | \,2 ^ {j - 1}} + a_j)} fi,S=fi,S+max(fi+1,S,fi+1,S2j1+aj)
因为求的是期望,而每一种宝物都只有 1 n \frac1n n1的可能性,所以最后要除以 n n n

最终答案即为 f 1 , 0 f_{1,0} f1,0,详见代码

Code:

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 16,maxm = 150,inf = 1e9;
int n,k,t,a[maxn],s[maxn];
double f[maxm][1 << maxn];
int read(){
    int x = 0,f = 1;
    char c = getchar();
    while(c < '0' || c > '9'){
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') x = x * 10 + (c ^ 48),c = getchar();
    return x * f;
}
int main(){
    k = read(),n = read();
    for(int i = 1; i <= n; i ++){
        a[i] = read();
        while(t = read()) s[i] |= 1 << (t - 1);
    }
    for(int i = k; i >= 1; i --){
        for(int S = 0; S < (1 << n); S ++){
            for(int j = 1; j <= n; j ++){
                f[i][S] += max(f[i + 1][S],(S & s[j]) == s[j] ? f[i + 1][S | (1 << (j - 1))] + a[j] : -inf);//取不到就赋值为负无穷
            }
            f[i][S] /= n;
        }
    }
    printf("%.6lf\n",f[1][0]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值