鸽巢原理以及poj2356

老规矩还是先介绍一下鸽巢原理

内容

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

鸽巢原理有第一抽屉原理:
第一抽屉原理
这就是说了,如果有n+1个物品放到n个抽屉里,必定有一个抽屉至少有两个物品。
如果n*m+1个物品放到n个抽屉里,至少有一个抽屉里面有(m+1)个物品。
如果是无限个物体放到有限个抽屉里,那必定有一个抽屉里面有无限个物品。

第二抽屉原理
如果有n*m-1个物品,放到n个抽屉里,那么有一个抽屉至多有m-1个物品。

上面都是显而易见的,即使不知道证明过程我们一想也是这么一回事,真正难的地方是我们如何去使用这个鸽巢原理去打题。那么这就要求我们做这类题目的时候,一定要先分清谁是抽屉谁是物品。只有把界限划分清楚,才能够解决题目。

poj2356

题目地址
http://poj.org/problem?id=2356

题目大意
题目大意就是先给出一个数n,接着再给出n个数,要你从这n个数中任意选择1个或多个数,使得其和是n的倍数。
如果找不到这样的答案 则输出0答案可能有多个,但智勇任意输出一个解就行。输出的第一行是选择元素的个数M,接着M行分别是选择的元素的值。

解题思路
首先找到数组的前缀和,也就是a[0], a[0]+a[1]…a[0]+a[1]+…+a[n]。我们用sum[i]表示从0到i的a数组和。(原因请继续往下看)
那么对于sum数组,如果能有sum[i]%n == 0,那就直接输出i和从0到i-1的值。
如果不能的话,我们知道sum[i]%n一定是在[1, n-1]之间的数字,那又通过前面我们知道,sum总共有n个数字,可范围却是n-1,所以这里的抽屉就是n-1,物品就是n个数字,根据鸽笼原理,那就至少有两个数字是相等的,这样就得到了sum[i] mod n == sum[j] mod n, 也就是说(sum[j]-sum[i]) mod n == 0(这里假设j大于i)。
接下来就是为什么先求了一个前缀和问题,上面我们知道抽屉是n-1个,我们运用的是第一抽屉原理,所以需要有n个物品对吧 ,前缀和正好构造出了n个物品,如果你不怕麻烦,随便选数字构造也行。
通过上面的证明,也说明了这个题没有无解的情况,无论如果输入的数字都是n个。

AC代码

#include <iostream>
#include <cstring>

using namespace std;

int vis[100005];
int a[100005];
int sum[100005];

int main()
{
	ios::sync_with_stdio(false);
	
	int n;
	
	cin >> n;
	
	memset(vis, 0, sizeof(vis));
	sum[0] = 0;
	
	for (int i=1; i<=n; i++)
	{
		cin >> a[i];
		sum[i] = sum[i-1]+a[i];
	}
	
	for (int i=1; i<=n; i++)
	{	//第一种情况
		if (sum[i]%n == 0)
		{
			cout << i << endl;
			
			for (int j=1; j<=i; j++)
			{
				cout << a[j] << endl;	
			}
			
			break;
		} //第二种情况
		else if (vis[sum[i]%n])
		{
			cout << i-vis[sum[i]%n] << endl;
			
			for (int j=vis[sum[i]%n]+1; j<=i; j++)
			{
				cout << a[j] << endl;
			}
			
			break;
		}
		//标记出现过的sum%n
		vis[sum[i]%n] = i;
	}
	
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值