zoukankan      html  css  js  c++  java
  • HDU4336 Card Collector 容斥定理 Or 概率DP

    首先这题可以用期望DP来计算最后的期望值,由于这题每张卡片对应的概率是不相同的,所以不能像POJ-2096那样dp[i]表示拿到了i 张卡片来表示状态,而是要开一个 1<<N的状态来压缩状态表示拿到不用的卡片的期望值。对于给定的N,我们有dp[(1<<N)-1]=0,因为这已经是最后的状态了。

    对于dp[i] 我们需要分析其能够到达的状态,如果 N=6, i 的二进制位为 011011,那么可能买零食不改变原来状态,也就是中了已经有了的卡片或者是没有中卡片,所以到达原来状态的概率是p[1]+p[2]+p[4]+p[5]+NONE,这一项是要移到待会儿方程的左边去解的,因为dp[i]还未知,不能够直接带入求解。那么 i 能够到达哪些状态呢?这里就是凡是为0的位都可以到达,前面写了个(1<<bit)^i 来判定是否为零错了,应该还是要 !((1<<bit) & i) 来判定靠谱...... 转移到下一个状态的概率就非常好算了,直接乘以该位对应的概率就可以了。

    代码如下:

    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    
    int N;
    
    double seq[25], dp[1100000], p[1100000];
    
    void pre()
    {
        int LIM = 1 << N;
        for (int i = 0; i < LIM; ++i) {
            p[i] = 0;
            for (int j = 0; j < N; ++j) {
                if ((1 << j) & i) {  // 低位对应编号小的概率 
                    p[i] += seq[j+1];
                }    
            }
        }
    }
    
    int main()
    {
        int temp;
        double none, tot, myself;
        while (scanf("%d", &N) == 1) {
            dp[(1<<N)-1] = none = 0;
            for (int i = 1; i <= N; ++i) {
                scanf("%lf", &seq[i]);
                none += seq[i];
            }
            none = 1 - none;
            pre();
            for (int i = (1<<N)-2; i >= 0; --i) {
                tot = 0;
                myself = p[i] + none; 
                for (int j = 0; j < N; ++j) {
                    if (!((1 << j)&i)) { 
                        temp = i | (1 << j);
                        tot += seq[j+1] * dp[temp];
                    }
                }
                dp[i] = (tot + 1) / (1 - myself);
            }
            printf("%.6lf\n", dp[0]);
        }
        return 0;
    }

    这题真心不明白容斥定理是怎么来的。

    代码如下:

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    using namespace std;
    
    int N;
    
    double seq[25];
    
    int main()
    {
        int mask, odd;
        double sum, ret;
        while (scanf("%d", &N) == 1) {
            ret = 0;
            for (int i = 1; i <= N; ++i) {
                scanf("%lf", &seq[i]);
            }
            mask = 1<<N;
            for (int i = 1; i < mask; ++i) {
                odd = 0;
                sum =0;
                for (int j = 0; j < N; ++j) {
                    if ((1 << j) & i) {
                        ++odd;
                        sum += seq[j+1];
                    }
                }
                if (odd & 1) {  // 加奇减偶 
                    ret += 1./sum;
                }
                else {
                    ret -= 1./sum;        
                }
            }
            printf("%.6lf\n", ret);
        }
        return 0;     
    }
  • 相关阅读:
    请简单说一下你了解的端口及对应的服务?
    地址解析协议ARP和逆地址解析协议RARP
    IP地址分类
    OSI分层和五层协议
    对象如何晋升到老年代?
    JVM 垃圾回收机制,何时触发 MinorGC 等操作
    什么是引用?
    类加载机制
    Solaris10怎么创建flash archive
    RPC: program not registered (ZT)
  • 原文地址:https://www.cnblogs.com/Lyush/p/2623439.html
Copyright © 2011-2022 走看看