HDU1205 鸽巢原理/找规律

原创 2016年05月30日 20:17:27


1)

利用鸽巢原理,很简单做。

让所有相同种类的糖果分开,我们让最大数目的糖果作为挡板,放在其他糖果间。而为了让最大数目的糖果自己不会连续出现,所以确保每一个之间一定要有别的糖果,所以求得其他糖果数量之和,如果和大于等于(最大数目的糖果数目-1),问题就会得到解决。不用担心其他糖果会连续出现,如果有一种糖果连续出现,那么这种糖果的数量一定大于最大糖果,与假设不符,遂不成立。

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stack>
#include <vector>

using namespace std;

long long int sum=0;
int flag=0;
int main()
{
    int t; scanf("%d",&t);
    while(t--){

        int n; scanf("%d",&n);
        int num;
        flag=0;
        sum=0;
        int maxx=0;
        for(int l=1;l<=n;l++){
            scanf("%d",&num);
            maxx=max(maxx,num);
            sum+=num;
        }
        sum-=maxx;
        //cout<<sum<<endl;
        //cout<<maxx<<endl;
        if(maxx-1<=sum){
            flag=1;
        }
        if(flag){
            cout<<"Yes"<<endl;
        }
        else{
            cout<<"No"<<endl;
        }

    }
    return 0;
}



2)自己找规律做

Code:用栈或者数组模拟栈,如果两个糖果的数目相同,则用sum记录两个糖果数量之和略过,继续读数,读完以后将没有用sum记录的糖果的数目按大小压入栈,将最大的数和第二大的数不断减1,直到第二大的数等于第三大的数,然后将相同的两个数出栈(用sum+=两数之和),直到除了最大的数以外,其他所有数是两两相等,那么sum>=(此时最大数的值-1)就判定为Yes.

思想:两个糖果数目相等,则这两个糖果最后一定可以互相搭配的被吃完,而且可以在两个糖果中间放别的糖果,所以起到两重作用。Code中记录sum,以及相等就忽略/出栈,就起到了这两个作用。

注意:用到的变量要及时清零,注意特殊情况比如没有数入栈则直接判定为Yes,等。

(刚开始想用set存储,但因为set内元素不能被更改,只能删除以后再插入效率低,所以舍弃;队列再插入时就会插入到队尾(后放入的)而不是队首(先放入的)所以也舍弃。于是用栈,WA,以为超出栈的范围,于是数组模拟栈,后来发现是没有及时sum=0的原因,两者都能过。)

①栈

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stack>

using namespace std;
int matrix[1000010];
long long int sum=0;
int flag=0;
int main()
{
    int t; scanf("%d",&t);
    while(t--){
        memset(matrix,0,sizeof(matrix));
        sum=0;
        int n; scanf("%d",&n);
        int num;
        flag=0;
        for(int l=1;l<=n;l++){
            scanf("%d",&num);
            matrix[num]++;
            if(matrix[num]==2) {matrix[num]=0;sum+=(num*2);}
        }
        stack <int> qq;
        qq.push(0);
        for(int l=1;l<=1000000;l++){//for(;l<=1000010;),因为l==1000010越界了,所以输出了
            if(matrix[l]!=0){
                qq.push(l);
            }
        }

        int l3=-1,l2=-1,l1=-1;
        if(qq.size()==1){
            cout<<"Yes"<<endl;
            continue;
        }
        while(qq.size()>=3){
            l3=qq.top();qq.pop();
            l2=qq.top();qq.pop();
            l1=qq.top();qq.pop();
            l3-=(l2-l1);
            sum+=(l1*2);
            qq.push(l3);
        }
        l3=qq.top();
        if(sum>=(l3-1)){
            flag=1;
        }
        if(flag){
            cout<<"Yes"<<endl;
        }
        else{
            cout<<"No"<<endl;
        }

    }
    return 0;
}
②数组模拟栈:
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stack>
#include <vector>

using namespace std;
int matrix[1000010];
int stackk[1000010];
long long int sum=0;
int flag=0;
int main()
{
    int t; scanf("%d",&t);
    while(t--){
        memset(matrix,0,sizeof(matrix));
        memset(stackk,0,sizeof(stackk));
        sum=0;
        int n; scanf("%d",&n);
        int num;
        flag=0;
        for(int l=1;l<=n;l++){
            scanf("%d",&num);
            matrix[num]++;
            if(matrix[num]==2) {matrix[num]=0;sum+=(num*2);}
        }
        stackk[0]=0;
        int top=0;
        for(int l=1;l<=1000000;l++){
            if(matrix[l]!=0){
                stackk[++top]=l;
            }
        }
        if(top==0){
            cout<<"Yes"<<endl;
            continue;
        }
        int l3=-1,l2=-1,l1=-1;
        int l;
        for(l=top;l>=2;l=l-2){
            l3=stackk[l];
            l2=stackk[l-1];
            l1=stackk[l-2];
            l3-=(l2-l1);
            sum+=(l1*2);
            stackk[l-2]=l3;
        }
        l3=stackk[l];
        if(sum>=(l3-1)){
            flag=1;
        }
        if(flag){
            cout<<"Yes"<<endl;
        }
        else{
            cout<<"No"<<endl;
        }

    }
    return 0;
}
③参考别人的,直接找出规律,比我写的更接近问题本质

/*如果最大堆-次大堆<=1,那么问题肯定有解:
我们可以从最大和次大里面每次拿一个,然后等他们和第三大堆相等的时候
,每次从三堆里面各拿一个,等他们和第四大堆相等的时候
,每次从四堆里面各拿一个,这样一直拿完所有堆。
问题变成了能不能使得最大堆-次大堆<=1,所以之前我们会从次大堆之外的那些堆里面取,
来让最大堆减少,如果能减到:最大堆-次大堆<=1,那么原问题有解。
能否减到要看:
sum - max - max2 >= max - max2 - 1
是否成立,其中sum为总和,max为最大堆,max2为次大。
整理得:
2 * max - sum <= 1
*/
#include<stdio.h>
int main()
{
    int cas,n,max;
    scanf("%d",&cas);
    while(cas--)
    {
        __int64 sum;
        sum=max=0;
        scanf("%d",&n);
        while(n--)
        {
            int num;
            scanf("%d",&num);
            if(max<num) max=num;
            sum+=num;
        }
        if(2*max-sum<=1) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}







版权声明:本文为博主原创文章,未经博主允许不得转载。

一些有趣的鸽巢原理的题目

鸽巢原理也叫抽屉原理,是Ramsey定理的特例。也是编程爱好者必须掌握的研究离散问题中存在性问题的方法。  它的简单形式是 : 把n+1个物体放入n个盒子里,则至少有一个盒子里含有两个或两个以上的物...
  • lcj_cjfykx
  • lcj_cjfykx
  • 2014年12月03日 11:44
  • 2266

鸽巢原理简单应用

http://poj.org/problem?id=2356 从n个数里面取出一些数,这些数的和是n的倍数。并输出这些数。 先预处理出前n个数的和用sum[i]表示前i个数的和。若...
  • u013081425
  • u013081425
  • 2014年08月12日 20:27
  • 789

鸽巢原理(初识)(纯算法)

一.what? 鸽巢原理(抽屉原理)若把n个物体放在n - 1个抽屉中,至少有一个抽屉中放了两个物体。 它只能用于解决存在性问题?...
  • qq_30241305
  • qq_30241305
  • 2016年07月30日 22:35
  • 1370

浅谈容斥原理鸽巢原理(抽屉原理

容斥原理算法简述在集合S中至少具有,,…中的一个元素的个数是:主要运用场合与思路:简单的讲:容斥原理的最重要的应用就是去重。如果完成一件事情有n类方式,…,每一类进行方式有中方法(1 ...
  • wang2332
  • wang2332
  • 2017年07月31日 02:45
  • 510

优雅的利用鸽巢原理敲代码

写分布式的实验的时候遇到一个问题, 敲完了才发现自己这部分代码写得有一些问题: 问题是这样的,我需要对每次创建的一个对象赋一个id号码(需要唯一标识每个对象), 一开始我naive的写成了...
  • u011581550
  • u011581550
  • 2014年11月30日 10:27
  • 543

鸽巢(计数)排序--java

//鸽巢排序,去zte面试被问到一道算法题,后来才知道是鸽巢排序的思想,可用于统计数组中重复元素的个数 //调试时总是报数组越界异常,max=32,new数组的长度必须大于32,应为max+1; 菜鸟...
  • Christlxl
  • Christlxl
  • 2016年07月07日 21:20
  • 269

排序算法之鸽巢排序

计数排序     计数排序的执行速度快于任何一种排序,但其却需要很大的辅助空间。计数排序的辅助数组的大小取决与待排序数组的数值范围,辅助空间的大小为待排序数组中的最大值与最小值之差加1。比如有序列{1...
  • u010647471
  • u010647471
  • 2015年10月29日 22:41
  • 910

poj2356(鸽巢原理)

http://poj.org/problem?id=2356 Find a multiple Time Limit: 1000MS Memory Limit: 65536K Total ...
  • lanjiangzhou
  • lanjiangzhou
  • 2013年05月30日 11:06
  • 465

鸽巢原理的应用

假设最大和最小数分别为max和min,将n个数投入n+1个桶中,桶与桶的间距gap=(max-min)/(n+1),每个数x所在的桶的位置是x/gap,利用的鸽巢原理,至少一个桶是空的,那么两个相邻数...
  • wang19890326
  • wang19890326
  • 2013年03月14日 10:50
  • 471

HDU 1205(鸽巢原理)

HOHO,终于从Speakless手上赢走了所有的糖果,是Gardon吃糖果时有个特殊的癖好,就是不喜欢将一样的糖果放在一起吃,喜欢先吃一种,下一次吃另一种,这样;可是Gardon不知道是否存在一种吃...
  • Feynman1999
  • Feynman1999
  • 2017年08月02日 13:15
  • 134
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:HDU1205 鸽巢原理/找规律
举报原因:
原因补充:

(最多只允许输入30个字)