ACM-抽屉原理

来源:互联网 发布:网易云音乐网络电视版 编辑:程序博客网 时间:2024/06/05 13:33

抽屉原理有许多其它的名字,也有很多不同的描述,这里我就使用抽屉和着色去表示和描述这个定理。

简单形式的抽屉原理是显而易见的:如果使用n种颜色给n+1个物体着色,那么无论怎么做,都必定会有两个物体被着成相同的颜色。

但是,仅仅是简单形式的抽屉原理的具体应用也并不是其表面上看起来那么简单的,它注重的是一个分析和思考的过程,抽屉原理的内容仅仅充当这一过程中简单但不可或缺的一步。具体的应用可以参考《组合数学》鸽巢原理一章,大家就会发现抽屉原理的许多妙用,但是不容易想到。

其实,抽屉原理还有更复杂的形式,但是比较复杂,仅作扩展。


下面以一道题为例,进行分析,HDOJ:1808,题目如下:

Halloween treats

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 499    Accepted Submission(s): 161
Special Judge


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 51 2 3 7 53 67 11 2 5 13 170 0
 

Sample Output
3 52 3 4
 
 题意:
有c个孩子,去n个邻居家要糖果,现在已知每个邻居所能给的糖果数ai,问怎么个要法能保证全部所得的糖果能被c个孩子平分。
分析:
参考《组合数学》鸽巢原理一章中的应用3,我们考虑前k个邻居的糖果总数,那么这样的和一共有n个,a1,a1+a2,...,a1+...+an,如果将他们分别除以孩子的个数c,那么余数只可能在1~c-1之间,换句话说,和有n个,而余数有c-1个,并且从题目中可知c<=n,那么根据抽屉原理可知,必然有两个和的余数是相同的,这也就意味着这两个和中包含的公有项的和能被c整除,即为所求答案,详细推导见书上。
源代码:
#include <cstdio>#include <cstring>const int MAXN = 1e5+5;int a[MAXN], SumMod[MAXN], flag[MAXN];int main(){    int c, n;    while(~scanf("%d%d", &c, &n) && (c+n))    {        SumMod[0] = 0;        memset(flag, 0, sizeof(flag));        for(int i=1; i<=n; ++i)            scanf("%d", &a[i]);        for(int i=1; i<=n; ++i)        {            SumMod[i] = (SumMod[i-1] + a[i]) % c;  // 处理前缀和,并取模            if(flag[SumMod[i]] == 0)                flag[SumMod[i]] = i;            else                                   // 如果相同的余数在前面出现过            {                int j = flag[SumMod[i]] + 1;                int k = j;                for(; j<=i; ++j)                   // 公共项即为答案                    if(j == k) printf("%d", j);                    else printf(" %d", j);                break;            }        }        puts("");    }    return 0;}

其他相关的题目还有,HDOJ:1205,3303。POJ:2356,3370。

0 0
原创粉丝点击