7.16T1

这是道水题!?反正大佬说它水,那他就水着吧,我反正没觉得

我是实在没想到这道题就码了30行,不过这道题证明我现在对状压有了一丝丝敏感度,想到了要状压,并且想出了状压的状态,然而我连题都没看懂,样例也没搞出来,就随便骗了点分

这道题的状态就是用1代表这件商品被买过了,0表示没买过,由于他每次拿出哪件物品的都有可能,当然了也可能什么都没拿出来,那这个状态就有3个来源

1.这次买到了没买过的物品

2.这次买到了买过的物品

3.这次什么也没买到

其实2和3是一样的,都是由当前状态转移到当前状态,不过2和3共同的概率我们不可能直接得到,那就只能用1减去第一种情况出现的概率,我们试着列一下转移方程

$f[i]=∑(f[i-j]*p[j])+(1-∑p[j])*f[i]+1$

这个东西有了上面那些应该就很好理解了j代表的是取出来的那个1,当然必要时要把它变成第j件物品,也就是它是第几个一,这个应该是状压的常见套路吧,这个+1是因为不管你从那个状态来你都要多买一次,其实这个+1就看你怎么理解了,他应该是可以有不同的理解方式,我们给这个式子移一下项,他就变成了整个样子

$f[i]=frac{(∑(f[i-j]*p[j])+1)}{∑p[j]}$

然后愉快的转移就好了

 1 #include<iostream>
 2 #include<cstdio>
 3 #define ll long long
 4 #define maxn 22
 5 using namespace std;
 6 int n;
 7 ll ans;
 8 int c[1<<maxn];
 9 ll W[maxn];
10 double gl[maxn],f[1<<maxn];
11 int lowbit(int x)
12 {
13     return x&(-x);
14 }
15 int main()
16 {
17     scanf("%d",&n);
18     for(int i=0;i<n;++i)  {int ls=(1<<i);  c[ls]=i+1;}
19     for(int i=1;i<=n;++i)  {scanf("%lf%lld",&gl[i],&W[i]);  ans+=W[i];}
20     printf("%lld
",ans);
21     for(int i=1;i<(1<<n);++i)
22     {
23         double sum=0;
24         for(int k=i;k;k-=lowbit(k))
25         {
26             int ls1=lowbit(k);  int ls2=c[ls1];
27             f[i]+=f[i-ls1]*gl[ls2];  sum+=gl[ls2];
28         }
29         f[i]=(f[i]+1.000)/sum;
30     }
31     printf("%0.3lf
",f[(1<<n)-1]);
32     return 0;
33 }
View Code
原文地址:https://www.cnblogs.com/hzjuruo/p/11201870.html