【2015暑假】鸽巢原理总结 【算法思路+组合数学】

                                                                  组合数学之鸽巢原理

如果要把n+1物体放进n个盒子里,那么至少会有一个盒子包含2个或2个以上的物体。

现在问题来了:给你n个数,从中选出若干个数使得它们的和为n的倍数。

鸽巢原理表示:一定存在若干个连续的数,它们的和是n的倍数。

有的情况下,不光要知道一定存在,而且还要找出是哪些数,算法如下:

n = 4;

a[]:3  2  1  9

s[]:3  5  6  15   (注:)

先检查s[]中有没有某个s[i]%n==0,如果存在,那么这些数字它们加起来就可以整除n。如果不存在,那么由基本定理可知:必然会存在两个不同的和它们对n取余的余数相同,故部分和-= +  +…+  是n的倍数。

对于上面的例子一次求出s[]对n的余数:

yu[]:3  1  2  3

可知:和对4取余的余数均为3,故可以得到:2 + 1 + 9=12的和可以整除n。

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 #include <algorithm>
 5 #define N 100000
 6 
 7 using namespace std;
 8 
 9 
10 int main()
11 {
12     int n;
13     int a[N];
14     int s[N];
15     int yu[N];
16     
17     while(scanf("%d", &n)!=EOF)
18     {
19         for(int i=0; i<n; i++){
20             scanf("%d", &a[i]);
21         }
22         
23         bool flag=false;
24         int left=0, right;
25         s[0]=a[0];
26         for(int i=1; i<n; i++){
27             s[i]=s[i-1]+a[i];
28             if(s[i]%n == 0){
29                 flag=true;
30                 right=i; break;
31             }
32         }
33         if(flag){
34             printf("YES\n");
35             for(int i=0; i<=right; i++)
36             {
37                 printf("%d ", a[i]);
38             }
39         }else{
40             for(int i=0; i<n; i++){
41                 yu[i]=s[i]%n;
42             }
43             //查找yu[]里面哪两个数相等
44             for(int i=0; i<n; i++)
45             {
46                 left=i;
47                 for(int j=i+1; j<n; j++){
48                     if(yu[i]==yu[j]){
49                         right=j; break;
50                     }
51                 }
52             }
53             printf("YES\n");
54             for(int i=left+1; i<=right; i++)
55             {
56                 printf("%d ", a[i]);
57             }
58         }
59     }
60     return 0;
61 }
View Code

 

posted @ 2015-07-21 06:11  我喜欢旅行  阅读(1371)  评论(0编辑  收藏  举报