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(){;}
只要是活着的东西,就算是神我也杀给你看。