HDU 4336 Card Collector 期望dp+状压
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4336
Card Collector
Memory Limit: 32768/32768 K (Java/Others)
输入
The first line of each test case contains one integer N (1 <= N <= 20), indicating the number of different cards you need the collect. The second line contains N numbers p1, p2, ..., pN, (p1 + p2 + ... + pN <= 1), indicating the possibility of each card to appear in a bag of snacks.
Note there is at most one card in a bag of snacks. And it is possible that there is nothing in the bag.
输出
Output one number for each test case, indicating the expected number of bags to buy to collect all the N different cards.
You will get accepted if the difference between your answer and the standard answer is no more that 10^-4.
样例输入
1
0.1
2
0.1 0.4
样例输出
10.000
10.500
题意
小时候买零食的时候,里面都会附带一张卡片(或没有),现在告诉你每包零食里面每一种卡片出现的概率,问你集齐这n类卡片需要买的零食的期望包数。
题解
由于卡片种类最多就20多种,所以状压一下从dp[(1<<n)-1]地推到dp[0]就可以了。
dp[i]表示已经集齐状态为i的卡片,平均还要买多少包才能集齐所有的。
转移方程:dp[i]=(1-sp)*dp[i]+sigma(pro[j]*dp[i^(1<<j)])+1
(这里要保证i&(1<<j)==0,并且sp=sigma(pro[j]).)
移项得:dp[i]=sigma(pro[j]*dp[i^(1<<j)]+1)/(1-(1-sp))
。
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf
typedef __int64 LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;
const int INF=0x3f3f3f3f;
const LL INFL=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-9;
const double PI = acos(-1.0);
//start----------------------------------------------------------------------
double dp[1<<21];
double pro[22];
int n;
int main() {
while(scf("%d",&n)==1&&n){
rep(i,0,n){
scf("%lf",&pro[i]);
}
dp[(1<<n)-1]=0.0;
for(int i=(1<<n)-2;i>=0;i--){
dp[i]=0;
double sp=0;
for(int j=0;j<n;j++){
if(i&(1<<j)) continue;
sp+=pro[j];
dp[i]+=pro[j]*dp[i^(1<<j)];
}
dp[i]+=1;
dp[i]/=sp;
}
prf("%.5lf\n",dp[0]);
}
return 0;
}
//end-----------------------------------------------------------------------
容斥也可以做:
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf
typedef __int64 LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;
const int INF=0x3f3f3f3f;
const LL INFL=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-9;
const double PI = acos(-1.0);
//start----------------------------------------------------------------------
double pro[22];
int n;
int main() {
while(scf("%d",&n)==1&&n){
rep(i,0,n){
scf("%lf",&pro[i]);
}
double ans=0;
for(int i=1;i<(1<<n);i++){
double sp=0;
int cnt=0;
for(int j=0;j<n;j++){
if(i&(1<<j)){
sp+=pro[j];
cnt++;
}
}
if(cnt%2) ans+=1.0/sp;
else ans-=1.0/sp;
}
prf("%.5lf\n",ans);
}
return 0;
}
//end-----------------------------------------------------------------------