容斥定理+鸽巢原理

今天开会了,协会只留了18个人,好残酷好悲伤,竞争激烈,但我可以的。呵…明天来更新这个算法,先洗洗澡睡觉,打了四个小时的球,累的像狗一样,晚安…
.

容斥定理

先举例子:

在概率论当中容斥定理就有体现:
例如:事件A,B,C;
求:三个事件中至少有一个事件发生的概率P;
P = P(A)+ P( B ) + P(C)-P(AB)-P(BC)-P(AC)+P(ABC)

也就是 : .P = 一个事件发生的概率 + 三个事件同时发生的概率 两个事件发生的概率 ;
用图来表示就是这样;
两两重叠的部分要减去,这样的话,三三重叠的部分(A^ B ^ C)就减了三次,所以在最后要加上P(ABC)
0
上面举了例子,下面说一说,容斥定理的定义:
容斥原理:在计数时,必须注意无一重复,无一遗漏。为了使重叠部分不被重复计算,人们研究出一种新的计数方法,这种方法的基本思想是:先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理。

公式表述

在这里插入图片描述
简述:
四个字:奇加偶减. . . 意思就是,减去偶数个事件同时发生的概率,加上奇数个事件同时发生的概率;

.

怎样用代码实现呢?怎样用代码吧这个思维体现出来?
首先,要把这个思维转换一下;

在这里我们介绍一种方法那就是二进制枚举法;(套用学长的思路)

我们先来思考一下这个问题:如果要对n个物体进行选择,那么有多少种情况?

这个我们应该怎么做呢?每个问题只有两种情况,那就是选与不选,这就相当于十几个集合求并集,如果选的是奇数个物品那么我们应该去加的,如果选的是偶数的物品,那么我们应该是相减的,但是我们应该怎么选呢?我们要实现的目的就是每次选的时候我们呢要知道哦我们选了多少个。而且我们还要知道我们选看谁,那么该怎么办呢?这就用到二进制枚举法了,既然这个方法的名字和二进制有关那么我们肯定也要用到二进制了是吧;

假如我们有三件物品,我们会有8种选择方案,我们先把他们一一的列举出来2,看看有什么规律没;
他们所对应的十进制数

0 0 0 0

0 0 1 1

0 1 0 2

0 1 1 3

1 0 0 4

1 0 1 5

1 1 0 6

1 1 1 7

是不是一共这8种情况,看一下这些像不像是二进制呢?那么我们先把他们看一下他们对应的十进制数,把二进制写出来之后,大家有没有发现什么规矩呢?好像这些数字就是从0到2的n次方-1是吧。那么我们我们把这些数字遍历一下是不是就把所有可以选的情况全部遍历了呢?然后我们再用一个位运算,例如6对应的是1 0 1,我们可以分别取 1,0,1那么我们就知道了我们一共选择了两个物品,选择的物品分别是第一个物品和第三个物品。

代码实现

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n;//一共n个物品;
    scanf("%d",&n);
    for(int i=0;i<(1<<n);i++)//从0到2的n次方-1;
    {
        for(int j=0;j<n;j++)     //判断第j个物品有没有被选中;
           printf("%d ",1&(i>>j));
        printf("\n");
    }
    return 0;
}
 
/*
运行结果
3
0 0 0
1 0 0
0 1 0
1 1 0
0 0 1
1 0 1
0 1 1
1 1 1
*/

通过一道例题来操作一下容斥定理的应用,并详情解释:
How many integers can you find HDU - 1796(容斥定理应用)

鸽巢原理

鸽巢原理又叫抽屉原理,基础是排列组合;
桌子上有是个苹果,把这十个苹果放到九个抽屉里,无论怎么放,我们会发现至少会有一个抽屉里面至少放两个苹果。这一现象就是所说的“抽屉原理”。
更一般的表述:如果每一个抽屉代表一个集合,每一个苹果就可以代表一个元素。加入有n+1个元素放到n个集合中去,其中必定有一个集合里至少有两个元素。

偷学长的表述来借鉴一下:
在这里插入图片描述
大概就是这个意思,那么意思很简单,他有什么用呢,在编程里面怎么实现呢?
怎样运用呢?

比如我做过一道题是这样的,给了你 N+1 个数排成一个区间,然后让你判断有没有一个区间内的数的和能整除N;
首先答案是 绝对有
————————————————————————————————————
假设这个数组是 a[0] a[1] a[2] a[3] …a[n],一共n+1个数
我们可以依次求出a[0], a[0]+a[1],,a[0]+a[1]+a[2], …,a[0]+a[1]+a[2]…+a[n];
用sum数组存储前i个数的和对n取余的结果,我们知道如果有两个余数,sum[i] == sum[j] (假设 j>i),那么这两个区间内的数的总和,一定是n的倍数;
那么一个数对n取余的结果 x 的范围是:0<=x<=n-1;可能的结果可能有n-1个,但是现在有n+1个取模的结果,根据鸽巢原理或者抽屉定理的,肯定有两个余数相同,
————————————————————————————————————
所以肯定存在!一个区间的和是n的倍数

(这就是简单应用,想起来就挺简单的,想不起来就比较麻烦了)
.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值