容斥原理的迭代程序实现

    最简单的容斥原理的表达为
                     |A∪B| = |A| + |B| - |A∩B|
也就是A、B并集的元素个数是A、B元素个数之和再减去A、B交集的元素个数。
    扩展到n个集合的并集的一般形式有,
|A1∪A2∪…∪An| = Σ|Ai| - Σ|Ai∩Aj|+Σ|Ai∩Aj∩Ak| - … + |A1∩…∩An|×(-1)^(n+1)
    再考虑DeMorgan定理,也就是交集的补集与补集的并集的关系,以及并集的补集与补集的交集的关系。有
|A1补∩A2补∩…∩An补| = |S| - |A1∪A2∪…∪An|
其中S表示全集。
    在题目之中,比较容易求得的是|S|、|Ai|以及|Ai∩Aj|等等。利用这些及上述公式,就可以求出并集的元素个数以及补集的交集的元素个数。
    例如全集表示N以内的正整数,A1表示S中所有2的倍数,A2表示S中所有3的倍数,A3表示S中所有5的倍数。那么A1∩A2就是S中所有6的倍数,……。于是我们可以求出:1.至少拥有2、3、5其中之一作为因子的数的个数;2.既不是2的倍数、也不是3的倍数、也不是5的倍数的数的个数。
    容斥原理的程序实现有两种方法,一种是递归,一种是迭代。个人认为迭代更容易理解。考虑容斥原理的公式,我们需要把等式右边的每一项挨个算出来,因此要写一个for循环。循环要迭代多少次?很容易看到右边就是一个遍历取组合,所以一共要循环迭代2^n-1次。每一次迭代的循环变量i表示什么含义?使用二进制数。例如i的二进制表示为1101,就代表A1∩A3∩A4;如果是1000,就代表A4;……。这样就把i从1到2^n-1的每一个数与容斥原理的等式右边的每一项一一对应起来。循环框架也就构建成功。剩下的就是写循环体具体去求每一项。
    给定一个i,如何判断到底是哪一位有1呢。这需要再用一个循环再加上移位运算即可。i一共可能有n位,挨个去判断每一位上是否为1即可。综上,典型的写法大概如下
for(int i=1;i<(1<<n);++i){
    for(int j=0;j<n;++j){
        if ( ( i >> j ) & 1  )
            符合这个条件表示要计算Aj,j的取值范围为[0,n)   
    }
}
    hdu的1695、1796、4135都是容斥原理的基本题,比较容易就能实现。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值