您的位置:首页 > 其它

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

2015-07-21 06:11 489 查看
组合数学之鸽巢原理

如果要把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。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#define N 100000

using namespace std;

int main()
{
int n;
int a
;
int s
;
int yu
;

while(scanf("%d", &n)!=EOF)
{
for(int i=0; i<n; i++){
scanf("%d", &a[i]);
}

bool flag=false;
int left=0, right;
s[0]=a[0];
for(int i=1; i<n; i++){
s[i]=s[i-1]+a[i];
if(s[i]%n == 0){
flag=true;
right=i; break;
}
}
if(flag){
printf("YES\n");
for(int i=0; i<=right; i++)
{
printf("%d ", a[i]);
}
}else{
for(int i=0; i<n; i++){
yu[i]=s[i]%n;
}
//查找yu[]里面哪两个数相等
for(int i=0; i<n; i++)
{
left=i;
for(int j=i+1; j<n; j++){
if(yu[i]==yu[j]){
right=j; break;
}
}
}
printf("YES\n");
for(int i=left+1; i<=right; i++)
{
printf("%d ", a[i]);
}
}
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: