HDU 4336 Card Collector (期望DP+状态压缩 或者 状态压缩+容斥)

题意:有N(1<=N<=20)张卡片,每包中含有这些卡片的概率,每包至多一张卡片,可能没有卡片。求需要买多少包才能拿到所以的N张卡片,求次数的期望。

析:期望DP,是很容易看出来的,然后由于得到每张卡片的状态不知道,所以用状态压缩,dp[i] 表示这个状态时,要全部收齐卡片的期望。

由于有可能是什么也没有,所以我们要特殊判断一下。然后就和剩下的就简单了。

另一个方法就是状态压缩+容斥,同样每个状态表示收集的状态,由于每张卡都是独立,所以,每个卡片的期望就是1.0/p,然后要做的就是要去重,既然要去重,

那么就是得用容斥原理了。

代码如下:

期望DP+状态压缩

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <set>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <cctype>
#include <cmath>
#include <stack>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
//#include <tr1/unordered_map>
#define freopenr freopen("in.txt", "r", stdin)
#define freopenw freopen("out.txt", "w", stdout)
using namespace std;
//using namespace std :: tr1;

typedef long long LL;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const double inf = 0x3f3f3f3f3f3f;
const LL LNF = 0x3f3f3f3f3f3f;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int maxn = (1<<20) + 5;
const LL mod = 10000000000007;
const int N = 1e6 + 5;
const int dr[] = {-1, 0, 1, 0, 1, 1, -1, -1};
const int dc[] = {0, 1, 0, -1, 1, -1, 1, -1};
const char *Hex[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
inline LL gcd(LL a, LL b){  return b == 0 ? a : gcd(b, a%b); }
int n, m;
const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
inline int Min(int a, int b){ return a < b ? a : b; }
inline int Max(int a, int b){ return a > b ? a : b; }
inline LL Min(LL a, LL b){ return a < b ? a : b; }
inline LL Max(LL a, LL b){ return a > b ? a : b; }
inline bool is_in(int r, int c){
    return r >= 0 && r < n && c >= 0 && c < m;
}
double dp[maxn];
double p[25];

int main(){
    while(scanf("%d", &n) == 1){
        double pp = 1.0;
        for(int i = 0; i < n; ++i){
            scanf("%lf", p+i);
            pp -= p[i];
        }
        dp[(1<<n)-1] = 0.0;
        for(int i = (1<<n)-2; i >= 0; --i){
            double have = 0.0, sum = 1.0;
            for(int j = 0; j < n; ++j)
                if(i&(1<<j))  have += p[j];
                else sum += p[j] * dp[i|(1<<j)];
            dp[i] = sum / (1.0 - pp - have);
        }
        printf("%.4f\n", dp[0]);
    }
    return 0;
}

状态压缩+容斥

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <set>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <cctype>
#include <cmath>
#include <stack>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
//#include <tr1/unordered_map>
#define freopenr freopen("in.txt", "r", stdin)
#define freopenw freopen("out.txt", "w", stdout)
using namespace std;
//using namespace std :: tr1;

typedef long long LL;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const double inf = 0x3f3f3f3f3f3f;
const LL LNF = 0x3f3f3f3f3f3f;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int maxn = (1<<20) + 5;
const LL mod = 10000000000007;
const int N = 1e6 + 5;
const int dr[] = {-1, 0, 1, 0, 1, 1, -1, -1};
const int dc[] = {0, 1, 0, -1, 1, -1, 1, -1};
const char *Hex[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
inline LL gcd(LL a, LL b){  return b == 0 ? a : gcd(b, a%b); }
int n, m;
const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
inline int Min(int a, int b){ return a < b ? a : b; }
inline int Max(int a, int b){ return a > b ? a : b; }
inline LL Min(LL a, LL b){ return a < b ? a : b; }
inline LL Max(LL a, LL b){ return a > b ? a : b; }
inline bool is_in(int r, int c){
    return r >= 0 && r < n && c >= 0 && c < m;
}
double p[25];

int main(){
    while(scanf("%d", &n) == 1){
        for(int i = 0; i < n; ++i) scanf("%lf", p+i);
        double ans = 0.0;
        for(int i = 1; i < (1<<n); ++i){
            int cnt = 0;
            double sum = 0.0;
            for(int j = 0; j < n; ++j)  if(i&(1<<j)){
                sum += p[j];
                ++cnt;
            }
            ans += (cnt & 1) ? 1.0/sum : -1.0/sum;
        }
        printf("%f\n", ans);

    }
    return 0;
}
时间: 2024-12-24 22:48:41

HDU 4336 Card Collector (期望DP+状态压缩 或者 状态压缩+容斥)的相关文章

hdu 4336 Card Collector(期望 dp 状态压缩)

Problem Description In your childhood, do you crazy for collecting the beautiful cards in the snacks? They said that, for example, if you collect all the 108 people in the famous novel Water Margin, you will win an amazing award. As a smart boy, you

hdu 4336 Card Collector(期望)

http://acm.hdu.edu.cn/showproblem.php?pid=4336 有N种卡片,每一袋零食里面最多有一张卡片,给出一袋零食里面每种卡片的概率,问平均要买多少袋零食能收集到所有的卡片. 状态压缩一下,共有1<<n-1个状态,设dp[sta]表示当前状态到目标状态平均买的零食数目,已知终态dp[1<<n-1] = 0,dp[sta]可由一下状态得到: 这一袋零食里没有卡片,概率为p(没有一张卡片的概率),状态转移到sta: 这一袋零食里面有卡片j,但是他已经拥

HDU 4336 Card Collector(概率DP)

 题意:有n种卡片,吃零食的时候会吃到一些卡片,告诉你在一袋零食中吃到每种卡片的概率,求搜集齐每种卡片所需要买零食的袋数的期望. 思路:先状态压缩,然后概率DP 用d[i]表示由状态i到目标需要再买多少包,则状态转移方程为d[i] = p'*(d[i]+1) + sigma(d[ i | (1 << j) * p[i] ),然后相同项移到左边,最后就可以得到答案. #include<cstdio> #include<cstring> #include<cmat

HDU 4336 Card Collector(动态规划-概率DP)

Card Collector Problem Description In your childhood, do you crazy for collecting the beautiful cards in the snacks? They said that, for example, if you collect all the 108 people in the famous novel Water Margin, you will win an amazing award. As a

Hdu 4336 Card Collector (状态概率DP|容斥原理)

详细的题目大意与解析大家参考一下kuangbin的文章. kuangbin链接 这边说一下自己对于kuangbin代码以及容斥原理位元素枚举的理解与解释,希望对大家有所帮助. 状态DP AC代码:状态压缩的思想我就不赘述了,我也只是略懂,这边仅仅分析一下状态方程 由于量比较多,我这边有的便用文字代替,有利于描述. dp[i]表示i状态达到满状态(即收集满n个物品,以下称满状态)所需要的期望. 那么i状态当中收集了x的物品,剩余n-x个物品没有收集 那么dp[i]=p*dp[i]+p2*dp[i2

【期望DP】 HDU 4336 Card Collector

通道 题意:有n种卡片,吃零食的时候会吃到一些卡片,告诉你在一袋零食中吃到每种卡片的概率,求搜集齐每种卡片所需要买零食的袋数的期望 思路: 假设S状态中为1的数位表示还没有拿到的卡片,那么每次可能会拿到这其中的某一张卡片, 也可能拿到原来已经拿到的卡片, 还可能一张卡片也拿不到 后两种情况的状态不变.dp[0]=0;(表示每一种卡片都取完了,期望当然是0喽)dp[S]=sum*dp[S]+p[x1]dp[S^(1<<x1)]+p[x2]dp[S^(1<<x2)].....+1;su

hdu 4336 Card Collector (概率dp+位运算 求期望)

题目链接 Card Collector Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2711    Accepted Submission(s): 1277Special Judge Problem Description In your childhood, do you crazy for collecting the beaut

HDU 4336 Card Collector(状压 + 概率DP 期望)题解

题意:每包干脆面可能开出卡或者什么都没有,一共n种卡,每种卡每包爆率pi,问收齐n种卡的期望 思路:期望求解公式为:$E(x) = \sum_{i=1}^{k}pi * xi + (1 - \sum_{i = 1}^{k}pi) * [1 + E(x)]$,即能转换到x情况的期望+x情况原地踏步的期望. 因为n比较小,我们可以直接状压来表示dp[x]为x状态时集齐的期望.那么显然dp[111111111] = 0.然后我们状态反向求解.最终答案为dp[0]. 然后来看期望的求解:$E(x) =

HDU 4336——Card Collector——————【概率dp】

Card Collector Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3407    Accepted Submission(s): 1665Special Judge Problem Description In your childhood, do you crazy for collecting the beautiful