Find a multiple (POJ - 2356 )(鸽巢原理)

The input contains N natural (i.e. positive integer) numbers ( N <= 10000 ). Each of that numbers is not greater than 15000. This numbers are not necessarily different (so it may happen that two or more of them will be equal). Your task is to choose a few of given numbers ( 1 <= few <= N ) so that the sum of chosen numbers is multiple for N (i.e. N * k = (sum of chosen numbers) for some natural number k).
Input
The first line of the input contains the single number N. Each of next N lines contains one number from the given set.
Output
In case your program decides that the target set of numbers can not be found it should print to the output the single number 0. Otherwise it should print the number of the chosen numbers in the first line followed by the chosen numbers themselves (on a separate line each) in arbitrary order.

If there are more than one set of numbers with required properties you should print to the output only one (preferably your favorite) of them.
Sample Input
5
1
2
3
4
1
Sample Output
2
2
3

今天是开始系统的学习关于组合数学的相关知识,其实说编程需要一些数学知识,还不如说是数学转移到了编程。这种感觉一直从我开始学习编程到现在一直都在。
今天接触的第一个知识是鸽巢原理(抽屉原理)

这个原理比较好懂:如果n+1个物体被放进n个盒子,那么至少有一个盒子包含两个或更多的物体。

  例1:在13个人中存在两个人,他们的生日在同一月份里。

  例2:设有n对已婚夫妇。为保证有一对夫妇被选出,至少要从这2n个人中选出多少人?(n+1)(引自百度)

关键是起初在实战中很少或者说想不到运用。以这道题为引子。

分析:我们可以在设置一个sum数组,在记录各个值的同事,把1到i(1<=i<=n)的和一并求出

假设在这场情况下 存在有sum[i]%n==0,我们输出即可
如果所有的sum[i]取模都没有等于0的,这里就用上这个原理,
我们把所有的sum[i]都取模,若存在两个i和j 使得sum[i]==sum[j](此时sum中存的是模数)
那么(sum[j]-sum[i])%n==0,这样就找到了一个答案,那么会不会存在两个相等的sum呢,答案是肯定有。
所以的余数情况是1到n-1,我们可以看做是箱子,而n个sum则是鸽子,也就是说,必然存在两个模相等的sum。
代码

import java.util.Scanner;

public class Main 
{
    public static void main(String[]args)
    {
        Scanner sc=new Scanner(System.in);
        while(sc.hasNext())
        {
            int n=sc.nextInt();
            int a[]=new int[n+1];//保存各个数,输出需要
            int sum[]=new int[n+1];//和值
            boolean  sign=false;//在前期用来判断有没有找到是n的倍数的值
            for(int i=1;i<=n;i++)
            {
                a[i]=sc.nextInt();
                sum[i]+=sum[i-1]+a[i];
                if(!sign)
                {
                    if(sum[i]%n==0)
                    {
                        System.out.println(i);
                        for(int j=1;j<=i;j++)
                            System.out.println(a[j]);
                        sign=true;//如果找到就置为true
                    }
                }
            }
            if(!sign)//没有找到就使用鸽巢原理
            {
                for(int i=1;i<=n;i++)
                    sum[i]%=n;//去n的模
                int v[]=new int[n];//这个就相当于是箱子
                for(int i=1;i<=n;i++)
                {
                    if(v[sum[i]]==0)
                        v[sum[i]]=i;//在箱子里村的是编号数
                    else//如果不为说明之前已经有鸽子进入这个箱子,也就是说找到两个值了
                    {
                        int l=v[sum[i]];
                        System.out.println(i-l);
                        for(int j=l+1;j<=i;j++)
                            System.out.println(a[j]);//输出即可
                        break;
                    }
                }
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值