首页 > 代码库 > bzoj1076 奖励关 状压dp 概率dp

bzoj1076 奖励关 状压dp 概率dp

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1076

题意:给出n种物品,每种物品有牵制条件和价值,有k次选择机会,每次每个物品等概率出现,问平均情况下最大收益。(n<=15)

首先看到这个n的范围和限制条件就应该想到是状压。

定义数组f[i][j]为当前处在第i次抛物品时间,状态为j。

但是如果我们仅仅这样定义并正向转移就会遇到一个问题:我们是有可能从无效状态推出有效状态,进而得出错误的结论的。例如,1的限制条件为2、3、4,那么我们就有可能从f[3][0111(2)]推出f[4][1111(2)],进而得出错误的结论。

怎么办呢,倒推。可以确定的是,结尾状态一定是合法的。

技术分享
 1 //以后大概概率都倒推好了……
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<algorithm>
 6 using namespace std;
 7 const int maxk=105,maxn=20,maxa=(1<<15);
 8 int n,ka,a[maxn],qianti[maxn];
 9 double f[maxk][maxa];
10 int haha()
11 {
12     scanf("%d%d",&ka,&n);
13     for(int i=1;i<=n;i++)
14     {
15         scanf("%d",&a[i]);int x;
16         while(scanf("%d",&x)!=EOF&&x)
17             qianti[i]|=(1<<(x-1));
18     }
19     int att=(1<<n);
20     for(int i=ka;i;i--)
21         for(int j=0;j<att;j++)
22         {
23             for(int k=1;k<=n;k++)
24                 if((j&qianti[k])==qianti[k])
25                     f[i][j]+=max(f[i+1][j],f[i+1][j|1<<(k-1)]+a[k]);
26                 else f[i][j]+=f[i+1][j];
27             f[i][j]/=n;
28         }
29     printf("%0.6lf\n",f[1][0]);
30 }
31 int sb=haha();
32 int main(){;}
bzoj1076

 

bzoj1076 奖励关 状压dp 概率dp