鸽巢原理:hdu 1205 吃糖果+poj 2356 Find a multiple+poj 3370 Halloween treats
2015-02-11 23:36
671 查看
鸽巢原理
也称抽屉原理,原理简单但应用却很广泛。**
(一)基本原理
**
**n+1只鸽子飞回n个鸽巢,至少有一个鸽巢含有不少于2只的鸽子。
另一种表述:假如有n+1个元素放到n个集合中,其中必定至少有一个集合里有2个元素**
hdu 1205 吃糖果(基本原理)
题目大意
给定n种类型的糖果各自的数量,问吃糖果时能不能不是连续吃到同一种糖果。
解题思路
1.插空法,找到数量最多的糖果,假设有n个,则有n+1个区域(注意是区域,不仅仅能放一个元素哦!)可以填放其他类型的糖果,很容易猜到只要其他种类糖果之和小于等于n-1(中间的空),就可以满足条件。
X_X_X_X_X_X_X
2那么,为什么正确呢?这里用到了抽屉原理(鸽巢原理)。
假设有一种糖果在插孔的过程中出现了相邻的情况(我们的目的是不让他们相邻,出现一个就放入一个空里,所有糖果都这么处理,所以只需分析其中的一种糖果),那么所有的空都填满,数量>=n+1+1个才能出现相邻的情况(这句话体现了鸽巢原理!),此时与最多数量为n的假设矛盾!所以不会出现相邻的情况
即这道题只要满足其他类型糖果数量比n-1个空多就可以。
参考代码
#include <iostream> #include <cstdio> #include <algorithm> #include <map> #include <vector> #include <cstring> #include <cmath> #define eps 1e-8 using namespace std; typedef long long ll; const int maxn = 1e2+10; int main() { // freopen("input.txt","r",stdin); int T;scanf("%d",&T); while(T--){ int n;scanf("%d",&n); ll sum=0; int num,Max=-1; for(int i=0;i<n;i++){ scanf("%d",&num); sum+=num; Max=max(Max,num); } sum-=Max; //除了数目最大的糖果外其他糖果的个数 Max-=1; //表示插空法中空的个数-2 if(sum>=Max) printf("Yes\n"); else printf("No\n"); } return 0; }
//////////////////////////////////华丽的分割线///////////////////////////////////////
(二)定理
poj 2356 Find a multiple(定理)
第一遍做直接套用定义,比较容易理解,就是分为证明过程中(1)(2)两种情况,找到就输出结果,并终止循环。
#include <iostream> #include <cstdio> #include <algorithm> #include <map> #include <vector> #include <cstring> #include <cmath> #define eps 1e-8 using namespace std; typedef long long ll; const int maxn = 1e4+10; int n,a[maxn],sum[maxn]; void solve() { bool flag=true; for(int i=1;flag&&i<=n;i++) if(sum[i]==0){ printf("%d\n",i); for(int j=1;j<=i;j++) printf("%d\n",a[j]); flag=false; } else{ for(int j=1;j<i;j++) if(sum[i]==sum[j]) { printf("%d\n",i-j);//输出字符串个数 for(int k=j+1;k<=i;k++) printf("%d\n",a[k]); flag=false; break; } } return; } int main() { // freopen("input.txt","r",stdin); while(scanf("%d",&n)!=EOF){ sum[0]=0; //初始化部分,读入数据 for(int i=1;i<=n;i++){ scanf("%d",a+i); sum[i]=(sum[i-1]+a[i]%n)%n; } solve(); } return 0; }
poj 3370 Halloween treats(定理)
基本上是一样的题,如果同样用定义实现的话,查找会TLE的。
建议使用标记数组flag[]来实现,找到就标记当前位置,再次标记时就直接输出所求序列即可,查找时就不用二重循环了,只要初始化标记数组置0就好。
还有,建议求和数组值先取模,一是取模很耗时,二是先取模不会溢出数据,3370这道题数据比较强,容易溢出。
参考代码
#include <iostream> #include <cstdio> #include <algorithm> #include <map> #include <vector> #include <cstring> #include <cmath> #define eps 1e-8 using namespace std; typedef long long ll; const int maxn = 1e5+10; int c,n,a[maxn]; int sum[maxn]; int flag[maxn]; int main() { // freopen("input.txt","r",stdin); while(scanf("%d%d",&c,&n)!=EOF&&c+n){ sum[0]=0; memset(flag,0,sizeof(flag)); for(int i=1;i<=n;i++){ scanf("%d",a+i); sum[i]=(sum[i-1]+a[i]%c)%c; } //初始化部分 for(int i=1;i<=n;i++){ if(sum[i]==0){ for(int j=1;j<=i;j++) j==1?printf("%d",j):printf(" %d",j);puts(""); break; } else if(flag[sum[i]]>0){ for(int j=flag[sum[i]]+1;j<=i;j++) j==i?printf("%d",j):printf("%d ",j);puts(""); break; } else flag[sum[i]]=i; } } return 0; }
(三)推论
相关文章推荐
- 抽屉定理poj 3370|| hdu1808 Halloween treats || hdu 1205 吃糖果 ||poj 2356
- poj2356 Find a multiple(鸽巢原理)
- POJ 2356 Find a multiple (鸽巢原理)
- POJ 2356 Find a multiple(鸽巢原理)
- POJ 2356 Find a multiple 鸽巢原理
- POJ:2356 Find a multiple(鸽巢原理)
- poj 3370 Halloween treats&&poj 2356 Find a multiple
- POJ 2356 Find a multiple 鸽巢原理
- POJ-2356 Find a multiple(鸽巢原理)题目数据太垃圾了!!
- poj 2356 Find a multiple——鸽巢原理
- POJ 2356:Find a multiple (鸽巢原理)
- poj 2356 Find a multiple 鸽巢原理的简单应用
- poj 2356 Find a multiple(鸽巢原理+标记)
- poj 2356 Find a multiple(鸽巢原理)
- POJ 2356 Find a multiple(鸽巢原理(抽屉原理))
- poj 2356 Find a multiple(组合数学:鸽巢原理)
- poj 2356 Find a multiple[鸽巢原理]
- POJ 题目2356 Find a multiple(鸽巢原理)
- Find a multiple (POJ - 2356 )(鸽巢原理)
- POJ 2356 Find a multiple / 3370 Halloween treats 鸽巢原理