标签:
http://acm.hdu.edu.cn/showproblem.php?pid=4336
1 0.1 2 0.1 0.4
10.000 10.500
题目大意:共有n张卡,每次一包方便面,可能有p[i]概率获得第i张卡,也有可能没有卡获得,求拿到全部n张卡需要买的方便面的期望?
感觉做了这么多概率dp,还是离熟悉比较远
合集里看到的,结果一眼就看到是用状态压缩做,然后状态都出来了,转移就没什么难度了...
设dp[i]表示当前取到了i的二进制中位的为1的卡时,离达到目标状态还需要购买方便面的期望,初始状态:dp[(1<<n)-1]=0;
则dp[i]可以转化为:
①:下一袋方便面没有卡,或j卡已有,即:(∑p[j]+pp)*(dp[i]+1);
②:下一袋方面面存在j卡,且当前没有,即:(∑p[j]*(dp[i|(1<<j)]+1);
则状态转移方程为:dp[i]=(∑p[j]+pp)*(dp[i]+1)+∑p[j]*(dp[i|(1<<j)]+1);
化简后得:dp[i]=(∑p[j]*dp[i|(1<<j)]+1)/(1-∑p[j]-pp);
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN=(1<<20)+5;
int n,mx;
double p[25],pp,tmp;//pp表示没有卡的概率
double dp[MAXN];//dp[i]表示当前取到了i的二进制中位的为1的卡时,离达到目标状态还需要购买方便面的期望
int main() {
while(1==scanf("%d",&n)) {
mx=1<<n;
pp=1;
for(int i=0;i<n;++i) {
scanf("%lf",p+i);
pp-=p[i];
}
dp[mx-1]=0;
for(int i=mx-2;i>=0;--i) {
dp[i]=1;
tmp=pp;
for(int j=0;j<n;++j) {
if((i&(1<<j))==0) {//由仅比i状态多1张卡的状态转移
dp[i]+=p[j]*dp[i|(1<<j)];
}
else {//tmp表示再买一包时,里面没卡以及卡是已在i状态有时的概率和
tmp+=p[j];
}
}
dp[i]/=1-tmp;
}
printf("%.4lf\n",dp[0]);
}
return 0;
}
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN=(1<<20)+5;
int n,mx,cnt;
double p[25],tmp,ans;//tmp表示某一状态下
int main() {
while(1==scanf("%d",&n)) {
mx=1<<n;
ans=0;
for(int i=0;i<n;++i) {
scanf("%lf",p+i);
}
for(int i=1;i<mx;++i) {
cnt=0;
tmp=0;
for(int j=0;j<n;++j) {
if((i&(1<<j))!=0) {//统计达到i状态位为1的概率和
tmp+=p[j];
++cnt;
}
}
if((cnt&1)==0) {//偶数张卡
ans-=1.0/tmp;
}
else {//奇数张卡
ans+=1.0/tmp;
}
}
printf("%.4lf\n",ans);
}
return 0;
}
HDU-4336 Card Collector(状压概率DP||容斥原理)
标签:
原文地址:http://blog.csdn.net/idealism_xxm/article/details/51328473