zoukankan      html  css  js  c++  java
  • 【HDU1205/POJ2356/POJ3370】鸽巢原理专题

    鸽巢原理是组合数学的内容,通过它可以证明一些东西的存在性。今天做了三道有关这个原理的水题,作为对这个原理证明的巩固。

    HDU1205 吃糖果
    测试地址:吃糖果
    题目大意:n种数字,其中有aii(1in),要求将它们排成一个序列,使得序列中相邻两项不相同,问存不存在这种序列。
    做法:这个题目一看似乎没有头绪,我们不知道判断有解的条件,那么我们就考虑判断无解的条件。根据鸽巢原理,设最多的数字个数为s,数字总数为sum,若2s>sum+1,则必定不存在可能的序列。为什么呢?一个通俗易懂的证法是,我们在这个序列里逐个放入数字,先放一个出现最多的数字,再放一个其他数字,再放一个出现最多的数字……这样下去,如果出现最多的数字个数大于剩余数字个数+1(即s>(sums)+1)的话,就无论如何都会有两个这个数字相邻,所以当2s>sum+1时肯定无解。那么如果2ssum+1,是不是就肯定有解了呢?答案是肯定的。因为出现最多的数字出现了s次,那么接下来出现的数字出现次数肯定是s的,直接交替放置在上一次放置数字的中间即可,这样放置下去,肯定能找到一个合法的序列。那么我们就解决了这一道题。
    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define ll long long
    using namespace std;
    int T,n;
    ll sum=0,mx=0;
    
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            sum=mx=0;
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
            {
                ll a;
                scanf("%lld",&a);
                sum+=a,mx=max(mx,a);
            }
            if (mx*2<=sum+1) printf("Yes
    ");
            else printf("No
    ");
        }
    
        return 0;
    }
    

    POJ2356 Find a multiple
    测试地址:Find a multiple
    题目大意:n个正整数组成一个集合,找出一个子集,使得子集中数字之和为n的正整数倍。
    做法:用鸽巢原理可以证明,不存在无解的情况,并且解可以很容易的找出来。证明如下:设第i个数字为ai,再令S0=0,Sn=ni=1ai,我们可以得到一个序列S0,S1,...,Sn,这个序列中有n+1个数,而这些数除以n的余数仅有n种(0,1,...,n1),那么必定存在一对Si,Sj,使得这两个数除以n的余数相等,即SiSj(modn),则SjSi=kn。不妨设i<j,因为ai均为正整数,所以Sj>Si,所以k为一个正整数,而SjSi=jk=i+1ak,所以我们就找到了一个子集使得子集内数的和为n的正整数倍。因此我们只需要O(n)找到一对同余的Si,Sj,那么子集ai+1,...,aj就是一个答案。
    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define ll long long
    using namespace std;
    int n,a[10010],sum,sum0;
    bool vis[10010]={0};
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        vis[0]=1;sum=0;
        for(int i=1;i<=n;i++)
        {
            sum+=a[i];
            sum%=n;
            if (vis[sum])
            {
                sum0=0;
                int s,t=i;
                if (sum0==sum) s=1;
                else
                {
                    for(int j=1;j<=n;j++)
                    {
                        sum0+=a[j];
                        sum0%=n;
                        if (sum0==sum) {s=j+1;break;}
                    }
                }
                printf("%d
    ",t-s+1);
                for(int j=s;j<=t;j++)
                    printf("%d
    ",a[j]);
                break;
            }
            else vis[sum]=1;
        }
    
        return 0;
    }
    

    POJ3370 Halloween treats
    测试地址:Halloween treats
    题目大意:c个小孩要向n户人家要糖果(cn),第i户人家会给ai颗糖果,要找一些人家并向他们要糖果,且得到的糖果能被这些小孩平分,求一个方案。
    做法:这一题和上面那题几乎一样,因为cn,所以以上的证明对于这一题完全适用,那么使用一样的方法就可以找到一个合法的答案。
    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define ll long long
    using namespace std;
    int c,n,a[100010],sum,sum0;
    bool vis[100010]={0};
    
    int main()
    {
        while(scanf("%d%d",&c,&n)&&n!=0)
        {
            for(int i=1;i<=n;i++)
                scanf("%d",&a[i]);
            memset(vis,0,sizeof(vis));
            vis[0]=1;sum=0;
            for(int i=1;i<=n;i++)
            {
                sum+=a[i];
                sum%=c;
                if (vis[sum])
                {
                    sum0=0;
                    int s,t=i;
                    if (sum0==sum) s=1;
                    else
                    {
                        for(int j=1;j<=n;j++)
                        {
                            sum0+=a[j];
                            sum0%=c;
                            if (sum0==sum) {s=j+1;break;}
                        }
                    }
                    for(int j=s;j<=t;j++)
                        printf("%d ",j);
                    printf("
    ");
                    break;
                }
                else vis[sum]=1;
            }
        }
    
        return 0;
    }
    
  • 相关阅读:
    shell 文件夹总大小 du -sh 文件夹
    java dump
    图片上传-下载-删除等图片管理的若干经验总结2
    android开发之shape详解
    图片上传-下载-删除等图片管理的若干经验总结
    图片上传-下载-删除等图片管理的若干经验总结
    一个奇怪的Java集合问题
    小米开源文件管理器MiCodeFileExplorer-源码研究(0)-初步研究
    小米开源文件管理器MiCodeFileExplorer-源码研究(0)-初步研究
    APK文件浅析-Android
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793611.html
Copyright © 2011-2022 走看看