抽屉原理(鸽巢原理)

一、抽屉原理初介绍:

桌上有十个苹果,要把这十个苹果放到九个抽屉里,无论怎样放,我们会发现至少会有一个抽屉里面至少放两个苹果。这一现象就是我们所说的“抽屉原理”。 抽屉原理的一般含义为:“如果每个抽屉代表一个集合,每一个苹果就可以代表一个元素,假如有n+1个元素放到n个集合中去,其中必定有一个集合里至少有两个元素。” 抽屉原理有时也被称为鸽巢原理。它是组合数学中一个重要的原理。

二、抽屉原理详讲:

第一抽屉原理: 
原理1: 
把多于n+1个的物体放到n个抽屉里,则至少有一个抽屉里的东西不少于两件。

原理2 : 
把多于mn(m乘n)+1(n不为0)个的物体放到n个抽屉里,则至少有一个抽屉里有不少于(m+1)的物体。 

原理3 : 
把无穷多件物体放入n个抽屉,则至少有一个抽屉里 有无穷个物体。

第二抽屉原理: 
把(mn-1)个物体放入n个抽屉中,其中必有一个抽屉中至多有(m—1)个物体(例如,将3×5-1=14个物体放入5个抽屉中,则必定有一个抽屉中的物体数少于等于3-1=2)。

三、构造抽屉的方法:

运用抽屉原理的核心是分析清楚问题中,哪个是物件,哪个是抽屉。例如,属相是有12个,那么任意37个人中,至少有几个人属相相同呢?这时将属相看成12个抽屉,则一个抽屉中有 37/12,即3余1,余数不考虑,而向上考虑取整数,所以这里是3+1=4个人,但这里需要注意的是,前面的余数1和这里加上的1是不一样的。因此,在问题中,较多的一方就是物件,较少的一方就是抽屉,比如上述问题中的属相12个,就是对应抽屉,37个人就是对应物件,因为37相对12多。

四、抽屉原理的简单应用:

抽屉原理的内容简明朴素,易于接受,它在数学问题中有重要的作用。许多有关存在性的证明都可用它来解决。 
1. 说明400人中至少有2个人的生日相同 
  解:将一年中的366天视为366个抽屉,400个人看作400个物体,由抽屉原理1可以得知:至少有2人的生日相同. 400/366=1…34,1+1=2 又如:我们从街上随便找来13人,就可断定他们中至少有两个人属相相同 
   
2. 幼儿园买来了不少白兔、熊猫、长颈鹿塑料玩具,每个小朋友任意选择两件,那么不管怎样挑选,在任意七个小朋友中总有两个彼此选的玩具都相同,试说明道理 
  解 :从三种玩具中挑选两件,搭配方式只能是下面六种:(兔、兔),(兔、熊猫),(兔、长颈鹿),(熊猫、熊猫),(熊猫、长颈鹿),(长颈鹿、长颈鹿)。把每种搭配方式看作一个抽屉,把7个小朋友看作物体,那么根据原理1,至少有两个物体要放进同一个抽屉里,也就是说,至少两人挑选玩具采用同一搭配方式,选的玩具相同.

是不是感觉这两个问题很LOW,其实我觉得也是,并没有体现抽屉原理的灵魂之美,下面我们就增加一点点难度

制造抽屉是运用原则的一大关键

3.从2、4、6、…、30这15个偶数中,任取9个数,证明其中一定有两个数之和是34。 
分析与解答 : 
我们用题目中的15个偶数制造8个抽屉: 
  此抽屉特点:凡是抽屉中有两个数的,都具有一个共同的特点:这两个数的和是34(这个地方各位大佬要看清楚了,是你制造抽屉,也就是说按照你的规定制造抽屉,很明显这道题我制造成{2},{4,30},{6,28},{8,26},{10,24},{12,22},{14,20},{16,18}这8个抽屉)。 
  现从题目中的15个偶数中任取9个数,由抽屉原理(因为抽屉只有8个),必有两个数可以在同一个抽屉中(符合上述特点).由制造的抽屉的特点,这两个数的和是34。 

4.从1、2、3、4、…、19、20这20个自然数中,至少任选几个数,就可以保证其中一定包括两个数,它们的差是12。 
分析与解答:在这20个自然数中,差是12的有以下8对:{20,8},{19,7},{18,6},{17,5},{16,4},{15,3},{14,2},{13,1}。 
  另外还有4个不能配对的数{9},{10},{11},{12},共制成12个抽屉(每个括号看成一个抽屉).只要有两个数取自同一个抽屉,那么它们的差就等于12,根据抽屉原理至少任选13个数,即可办到(๑•ั็ω•็ั๑)。

5.从1到20这20个数中,任取11个数,必有两个数,其中一个数是另一个数的倍数。 
分析与解答: 根据题目所要求证的问题,应考虑按照同一抽屉中,任意两数都具有倍数关系的原则制造抽屉.把这20个数按奇数及其倍数分成以下十组,看成10个抽屉(显然,它们具有上述性质): 
{1,2,4,8,16},{3,6,12},{5,10,20},{7,14},{9,18},{11},{13},{15},{17},{19},仔细研究一下,如果存在元素个数大于2的集合,是不是从这些集合中任意取出来两个都能满足一个数是另外一个数的倍数?(是的吧),这样设置抽屉的方法是不是很容易想到呢(๑•ั็ω•็ั๑) 
  从这10个数组的20个数中任取11个数,根据抽屉原理,至少有两个数取自同一个抽屉.由于凡在同一抽屉中的两个数都具有倍数关系,所以这两个数中,其中一个数一定是另一个数的倍数。

扫描二维码关注公众号,回复: 2531882 查看本文章

我们可以再难一点: 
6.某校校庆,来了n位校友,彼此认识的握手问候.请你证明无论什么情况,在这n个校友中至少有两人握手的次数一样多。 
分析与解答:共有n位校友,每个人握手的次数最少是0次,即这个人与其他校友都没有握过手;最多有n-1次,即这个人与每位到会校友都握了手.然而,如果有一个校友握手的次数是0次,那么握手次数最多的不能多于n-2次;如果有一个校友握手的次数是n-1次,那么握手次数最少的不能少于1次.不管是前一种状态0、1、2、…、n-2,还是后一种状态1、2、3、…、n-1,握手次数都只有n-1种情况.把这n-1种情况看成n-1个抽屉,到会的n个校友每人按照其握手的次数归入相应的“抽屉”,根据抽屉原理,至少有两个人属于同一抽屉,则这两个人握手的次数一样多。是不是很神奇呢?(๑• . •๑)

在有些问题中,“抽屉”和“物体”不是很明显的,需要精心制造“抽屉”和“物体”.如何制造“抽屉”和“物体”可能是很困难的,一方面需要认真地分析题目中的条件和问题,另一方面需要多做一些题积累经验。

五、抽屉原理在整除关系中的应用(例题一定要仔细看看哦):

把所有整数按照除以某个自然数m的余数分为m类,叫做m的剩余类或同余类,用[0],[1],[2],…,[m-1]表示.每一个类含有无穷多个数,例如[1]中含有1,m+1,2m+1,3m+1,….在研究与整除有关的问题时,常用剩余类作为抽屉.根据抽屉原理,可以证明:任意n+1个自然数中,总有两个自然数的差是n的倍数。(证明:n+1个自然数被n整除余数至少有两个相等(抽屉原理),不妨记为m=a1*n+b n=a2*n+b,则m-n整除n)。

1. 证明:任取8个自然数,必有两个数的差是7的倍数。 
分析与解答 :在与整除有关的问题中有这样的性质,如果两个整数a、b,它们除以自然数m的余数相同,那么它们的差a-b是m的倍数.根据这个性质,本题只需证明这8个自然数中有2个自然数,它们除以7的余数相同.我们可以把所有自然数按被7除所得的7种不同的余数0、1、2、3、4、5、6分成七类.也就是7个抽屉.任取8个自然数,根据抽屉原理,必有两个数在同一个抽屉中,也就是它们除以7的余数相同,因此这两个数的差一定是7的倍数。

2.对于任意的五个自然数,证明其中必有3个数的和能被3整除. 
证明:任何数除以3所得余数只能是0,1,2,不妨分别构造为3个抽屉: 
[0],[1],[2] 
  ①若这五个自然数除以3后所得余数分别分布在这3个抽屉中(即抽屉中分别为含有余数为0,1,2的数),我们从这三个抽屉中各取1个(如1~5中取3,4,5),其和(3+4+5=12)必能被3整除. 
  ②若这5个余数分布在其中的两个抽屉中,则其中必有一个抽屉至少包含有3个余数(抽屉原理),即一个抽屉包含1个余数,另一个包含4个,或者一个包含2个余数另一个抽屉包含3个。从余数多的那个抽屉里选出三个余数,其代数和或为0,或为3,或为6,均为3的倍数,故所对应的3个自然数之和是3的倍数. 
  ③若这5个余数分布在其中的一个抽屉中,很显然,从此抽屉中任意取出三个余数,同情况②,余数之和可被3整除,故其对应的3个自然数之和能被3整除. 
   
3.对于任意的11个整数,证明其中一定有6个数,它们的和能被6整除. 
证明:设这11个整数为:a1,a2,a3……a11 又6=2×3 
  ①先考虑被3整除的情形 
  由例2知,在11个任意整数中,必存在: 
  3|a1+a2+a3,不妨设a1+a2+a3=b1; 
  同理,剩下的8个任意整数中,由例2,必存在:3 | a4+a5+a6.设a4+a5+a6=b2; 
  同理,其余的5个任意整数中,有:3|a7+a8+a9,设:a7+a8+a9=b3 
  ②再考虑b1、b2、b3被2整除. 
  依据抽屉原理,b1、b2、b3这三个整数中,至少有两个是同奇或同偶,这两个同奇(或同偶)的整数之和必为偶数.不妨设2|b1+b2 
  则:6|b1+b2,即:6|a1+a2+a3+a4+a5+a6 
  ∴任意11个整数,其中必有6个数的和是6的倍数.

4. 任意给定7个不同的自然数,求证其中必有两个整数,其和或差是10的倍数. 
分析:注意到这些数除以10的余数即个位数字,以0,1,…,9为标准制造10个抽屉,标以[0],[1],…,[9].若有两数落入同一抽屉,其差是10的倍数,只是仅有7个自然数,似不便运用抽屉原则,再作调整:[6],[7],[8],[9]四个抽屉分别与[4],[3],[2],[1]合并,则可保证至少有一个抽屉里有两个数,它们的和或差是10的倍数. 
其实抽屉原理的一种更一般的表述为: 
  “把多于kn+1个东西任意分放进n个空抽屉(k是正整数),那么一定有一个抽屉中放进了至少k+1个东西。” 
  利用上述原理容易证明:“任意7个整数中,至少有3个数的两两之差是3的倍数。”因为任一整数除以3时余数只有0、1、2三种可能,所以7个整数中至少有3个数除以3所得余数相同,即它们两两之差是3的倍数。

如果问题所讨论的对象有无限多个,抽屉原理还有另一种表述:把无限多个东西任意分放进n个空抽屉(n是自然数),那么一定有一个抽屉中放进了无限多个东西。

抽屉原理的内容简明朴素,易于接受,它在数学问题中有重要的作用。许多有关存在性的证明都可用它来解决。

六、抽屉原理在染色问题中的应用:

1.正方体各面上涂上红色或蓝色的油漆(每面只涂一种色),证明正方体一定有三个面颜色相同. 
证明:正方形有6个面 由最多[(m-1)÷n]+1 得出[(6-1)÷2]+1=[2.5]+1=3

2.有5个小朋友,每人都从装有许多黑白围棋子的布袋中任意摸出3枚棋子.请你证明,这5个人中至少有两个小朋友摸出的棋子的颜色的配组是一样的。 
分析与解答: 首先要确定3枚棋子的颜色可以有多少种不同的情况,可以有:3黑,2黑1白,1黑2白,3白共4种配组情况,看作4个抽屉.根据抽屉原理,至少有两个小朋友摸出的棋子的颜色在同一个抽屉里,也就是他们所拿棋子的颜色配组是一样的。

3.假设在一个平面上有任意六个点,无三点共线,每两点用红色或蓝色的线段连起来,都连好后,问你能不能找到一个由这些线构成的三角形,使三角形的三边同色? 
分析与解答:首先可以从这六个点中任意选择一点,然后把这一点到其他五点间连五条线段,如图,在这五条线段中,至少有三条线段是同一种颜色,假定是红色,现在我们再单独来研究这三条红色的线。这三条线段的另一端或许是不同颜色,假设这三条线段(虚线)中其中一条是红色的,那么这条红色的线段和其他两条红色的线段便组成了我们所需要的同色三角形,如果这三条线段都是蓝色的,那么这三条线段也组成我们所需要的同色三角形。因而无论怎样着色,在这六点之间的所有线段中至少能找到一个同色三角形。

七、其他小问题

例1:( 六人集会问题 : 证明在任意6个人的集会上,或者有3个人以前彼此相识,或者有三个人以前彼此不相识。” ) 
是组合数学中著名的拉姆塞定理的一个最简单的特例,这个简单问题的证明思想可用来得出另外一些深入的结论。这些结论构成了组合数学中的重要内容—–拉姆塞理论。 
这个问题可以用如下方法简单明了地证出: 
  在平面上用6个点A、B、C、D、E、F分别代表参加集会的任意6个人。如果两人以前彼此认识,那么就在代表他们的两点间连成一条红线;否则连一条蓝线。考虑A点与其余各点间的5条连线AB,AC,…,AF,它们的颜色不超过2种。根据抽屉原理可知其中至少有3条连线同色,不妨设AB,AC,AD同为红色。如果BC,BD ,CD 3条连线中有一条(不妨设为BC)也为红色,那么三角形ABC即一个红色三角形,A、B、C代表的3个人以前彼此相识:如果BC、BD、CD 3条连线全为蓝色,那么三角形BCD即一个蓝色三角形,B、C、D代表的3个人以前彼此不相识。不论哪种情形发生,都符合问题的结论。

例2: 17个科学家中每个人与其余16个人通信,他们通信所讨论的仅有三个问题,而任两个科学家之间通信讨论的是同一个问题。证明:至少有三个科学家通信时讨论的是同一个问题。 
解:不妨设A是某科学家,他与其余16位讨论仅三个问题,由鸽笼原理知,他至少与其中的6位讨论同一问题。设这6位科学家为B,C,D,E,F,G,讨论的是甲问题。 
  若这6位中有两位之间也讨论甲问题,则结论成立。否则他们6位只讨论乙、丙两问题。这样又由鸽笼原理知B至少与另三位讨论同一问题,不妨设这三位是C,D,E,且讨论的是乙问题。 
  若C,D,E中有两人也讨论乙问题,则结论也就成立了。否则,他们间只讨论丙问题,这样结论也成立。 
  

八、代码实现

1题目:死神来了

题目描述:

有一天,王小子在遨游世界时,遇到了一场自然灾害。一个人孤独的在一个岛上,没有吃的没有喝的。在他饥寒交迫将要死亡时,死神来了。由于这个死神在成神之前是一个数学家,所以他有一个习惯,会和即死之人玩一个数学游戏,来决定是否将其灵魂带走。游戏规则是死神给王小子两个整数n(100<=n<=1000000),m(2<=m<=n),在1~n个数中,随机取m个数,问在这m个数中是否一定存在一个数是另一个数的倍数,是则回答“YES",否则”NO"。如果王小子回答正确,将有再活下去的机会。但是他很后悔以前没有好好学习数学,王小子知道你数学学得不错,请你救他一命。
  • 1
  • 2

输入: 
有多组测试数据,不多于10000; 
每组有两个数n,m; 
以文件结束符EOF为结束标志。

输出: 
输出”YES”或”NO”。

样例输入:

100 80 
100 20

样例输出:

YES 
NO

思路:这题用到了鸽笼原理(有n+1件或n+1件以上的物品要放到n个抽屉中,那么至少有一个抽屉里有两个 或两个以上物品。),在本题,我们m看作为m个鸽笼, 我们将1到N所有数的倍数分组,最大分组数为p=N / 2 + (N & 1),看作p只鸽子,问是否能把这p只鸽子 放入到m个笼子里,保证每只笼子只有一只鸽子。比如100的分组为,此处运用二进制的思想 
A1 = {1, 1*2,1*4…1*64} 
A2 = {3,3*2,3*4…3*32} 
… 
… 
A25 = {49,49*2} 
… 
… 
A50 = {99} 
细心的同学可能已经发现了每个子集都是奇数开头的,而且在一个集合中,后一个元素总是前一个元素的2倍,这样就能够保证该集合中任意两 个元素的,其中一个元素是另外一个元素的倍数,而且因为每次都要乘2,所以每个集合除了开头是奇数,后面的元素均为偶数,这样也方 便我们算有多少个集合,即有多少个抽屉 
所以公式为:n = (n>>1) + (n&1) ; (๑• . •๑)

AC代码为:

#include<iostream>
using namespace std;  
int main()  
{  
    int n,m;
    while(cin>>n>>m){  
        n = (n>>1) + (n&1);  
        if(m>n) cout<<"YES"<<endl; 
        else cout<<"NO"<<endl;  
    }  
    return 0;  
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2题目:Halloween treats

Problem Description:

Every year there is the same problem at Halloween: Each neighbour is only willing to give a certain total number of sweets on that day, no matter how many children call on him, so it may happen that a child will get nothing if it is too late. To avoid conflicts, the children have decided they will put all sweets together and then divide them evenly among themselves. From last year’s experience of Halloween they know how many sweets they get from each neighbour. Since they care more about justice than about the number of sweets they get, they want to select a subset of the neighbours to visit, so that in sharing every child receives the same number of sweets. They will not be satisfied if they have any sweets left which cannot be divided.

Your job is to help the children and present a solution.

Input:

The input contains several test cases. 
The first line of each test case contains two integers c and n (1 ≤ c ≤ n ≤ 100000), the number of children and the number of neighbours, respectively. The next line contains n space separated integers a1 , … , an (1 ≤ ai ≤ 100000 ), where ai represents the number of sweets the children get if they visit neighbour i.

The last test case is followed by two zeros.

Output:

For each test case output one line with the indices of the neighbours the children should select (here, index i corresponds to neighbour i who gives a total number of ai sweets). If there is no solution where each child gets at least one sweet, print “no sweets” instead. Note that if there are several solutions where each child gets at least one sweet, you may print any of them.

Sample Input:

4 5 
1 2 3 7 5 
3 6 
7 11 2 5 13 17 
0 0

Sample Output:

3 5 
2 3 4

题目大意:题目的意思是说有一群孩子在圣诞节给他们的邻居要糖果吃,但是他们想跟邻居要的糖果总数正好为他们总人数的倍数,为此,他们宁 愿少吃糖果,他们已经知道每个邻居分别会给多少糖果,现在请你给他们说一个方案,如果有多个方案,任意输出一个就行,注意:邻居 的数目大于等于孩子的数目,并且程序以输入的(0,0)结尾

虽然我说了个大概的题意,但是读者还是自己按照题目理解一遍比较好

代码实现:

#include<iostream>
#include <cstring>
using namespace std;
const int MAXN = 1e5+5;  
int candyNum[MAXN],sumMod[MAXN],flag[MAXN];//candyNum代表下标对应的邻居给的糖果数目,sumMod用来记录前面遍历过的邻居糖果的总和mod孩子数目的模,flag就是对应的抽屉,最多有 m-1个抽屉 
int main()  
{  
    int m,n;  
    while(cin>>m>>n && (m&n)){
        memset(candyNum,0,sizeof(candyNum));
        memset(sumMod,0,sizeof(sumMod));
        memset(flag,0,sizeof(flag));
        for(int i = 1;i<=n;i++)  
            cin>>candyNum[i];   
        if(candyNum[1]%m==0){//这个是为了处理当 m=n 且第一个邻居给的糖果数就已经能够均分,并且后面的邻居给的糖果不能均分的情况,比如m=n=4,candynum[]分别等于4,3,2,1,如果没有这步处理,你会发现不输出结果 
            cout<<1<<endl;
            continue;
        }  
        for(int i = 1;i<=n;i++){  
            sumMod[i] = (sumMod[i-1] + candyNum[i]) % m;// 这一步就是为了处理已经遍历过的这么多家邻居后是否能够将糖果均分? (用到了同余定理) 
            if(flag[sumMod[i]] == 0) flag[sumMod[i]] = i;//之前取模的过程中模为sumMod[i]的没遇到过 ,就给它赋值成i(主要是记录你第一次遇到这个余数是在访问哪一家邻居时遇到的,同时表示我一个一个遍历邻居时之糖果的总数%总人数所得的余数是否出现过) 
            else                                   // 如果我遍历到某个邻居时相同的余数在前面遍历邻居时出现过,就说明这两个邻居之间的那些邻居给的糖果数的和一定为m的倍数 (用到了同余定理,a+kb=a(mod b)),所以就将出现这个余数的第一个邻居的 后一个邻居的位置传给j,然后打印到第二次出现这个余数的那个邻居那即可 
            {     
                for(int j = flag[sumMod[i]] + 1; j<=i; j++){
                    if(j == (flag[sumMod[i]] + 1)) printf("%d", j);  
                    else printf(" %d", j);  
                } 
                break;  
            }  
        }
        puts("");  //换行 
    }  
    return 0;  
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

比如第一组数据: 
4 5 
1 2 3 7 5 
孩子人数:4 
邻居人数:5 
那么我从第一家邻居开始遍历求得的模是1,保存到flag[1] = 1(下标代表的是模),然后我又遍历到了第二家,这时我有3个糖果了,所以求得的模是3,保存到flag[3] = 2(值代表的是到第几家了) ,然后我遍历到了第三家,这时我有6个糖果,所以求得的模是2,保存到flag[2] = 3,然后我遍历到了第四家,这时我有13个糖果,所以求得的模是1,然后我发现flag[1]之前保存的已经有值了,那么说明我第flag[1]+1家到当前的第四家所有邻居给的糖果数的和是4的倍数(用到了同余定理,a+kb=a(mod b)),所以就输出了2 3 4 的结果

这道题其实也用到了抽屉的思想,说我有m-1(小孩的人数)个抽屉,然后我有n(n>=m)个邻居,我连续抽取m个邻居,一定会出现同模的情 况,因为余数情况最多为m-1种,即1~m-1,两个同模情况的中间所加糖果数的总和一定等于m的倍数

猜你喜欢

转载自blog.csdn.net/Destinymiao/article/details/81392751
今日推荐