个人对于鸽笼原理(抽屉原理)的理解,抽屉原理对于在写程序中的二重循环的优化还是很有用的,比如2016多校第三次训练的1011(HDU 5726) ,UVa202题中的循环小数,都是比较典型的(抽屉原理主要还是在有范围的或者有隐形范围题中)
对于多校1011题,在抽屉原理的应用是,在当输入的组数大于输入的限定范围m的时候必然会存在使其有至少两个点的差为相等的,
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
int b[200001]; //用来保存两点之间的曼哈顿距离
struct point
{
int x,y;
}a[10001]; //开一个结构体用来保存输入的数据
int main()
{
int t,m,n,i,j,flag,c;
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&m);
memset(b,0,sizeof(b));
for(i=0;i<n;i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
}
if(n>m) printf("Yes\n"); //运用抽屉原理
else
{
flag=1;
for(i=1;i<n;i++)
{
for(j=0;j<n-i;j++)
{
c=abs(a[j].x-a[j+i].x)+abs(a[j].y-a[i+j].y);
b[c]++;
if(b[c]>=2) {flag=0;break;} //查找相同的数值
}
if(flag==0) break;
}
if(flag==0) printf("YES\n");
else printf("NO\n");
}
}
}
对于UVA202循环小数;
这题在抽屉原理的应用是在一个数m的余数只有m-1种可能,超过m中必然重复;
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int s1[5000],s2[5000],s3[5000];
int main()
{
int n,m,a,b,i;
while(scanf("%d %d",&a,&b)!=EOF)
{
memset(s3,0,sizeof(s3));
n=0;
s1[n++]=a/b;
m=a%b;
while(m&&s3[m]==0) //通过一个数组进行标记,对于没有出现过的余数,对应的s3[m]==0 如果其不等于0,则已经出现过了;
{
s3[m]=n;
s2[n]=m;
s1[n]=(m*10)/b;
m=(m*10)%b;
n++;
}
printf("%d/%d = %d.",a,b,s1[0]);
for(i=1;i<n&&i<=50;i++)
{
if(m!=0&&s2[i]==m)
{
printf("(");
}
printf("%d",s1[i]);
}
if(m==0) printf("(0");
if(i>=50) printf("...");
printf(")");
printf("\n");
n=n-s3[m];
if(m==0) n=1;
printf(" %d = number of digits in repeating cycle\n\n",n);
}
}