随笔 - 68  文章 - 57  trackbacks - 0
<2009年3月>
22232425262728
1234567
891011121314
15161718192021
22232425262728
2930311234

常用链接

留言簿(8)

随笔分类(74)

随笔档案(68)

搜索

  •  

最新评论

阅读排行榜

评论排行榜

  一个经典的问题:给定n个数,求其中的任意一个子集满足集合中的每个元素值加和正好是n的倍数。刚开始怎么也没有思路,因为n很大,直接搜索显然是不行的。后来在组合数学书上找到了这个例题(晕,之前白看了,居然把这个经典的题目都给忘了),是抽屉原理的典型应用。
  假定n个数为a1,a2,...,an,前n项和分别是S1、S2、...、Sn,那么如果有一个Si模n是0,就是答案,否则,n个数模n的余数只能在1到n - 1之间,把余数作为抽屉,显然n个数放到n - 1个抽屉里面,肯定有两个数余数相等,这样取它们的差就得到了结果,算法复杂度是O(n)的。
  抽屉原理的应用都十分巧妙。还有一个例子,一个屋子里面有n个人,他们的最大年龄不超过k岁,问是否肯定存在2组人(两组没有重复的人),使得这两组人的年龄和相等。n个人的组合一共有2 ^ n种方法,注意到最大情况n的人的年龄和是n * k,这样如果2 ^ n > n * k,根据抽屉原理,一定存在两种组合他们的年龄和相等,而且没有重复的人(如果重复,把那个人删去就行了)。所以O(1)的时间就判断出了结果。
  不过在最开始做题目(PKU 2356)的时候,虽然代码很短,但是错了好多次。首先是数组开小了,然后发现输出的时候题目要求的是输出数但是我给输出下标了。最后的问题出在一个很关键的地方,在取模为零的时候,我本应该直接就记录产生了解,但是我以为取模为零的时候下次肯定会产生重复的标记,就没有特殊处理。其实如果第一个数取模就是0的话,就有可能后面不产生重复的标记,这样我的程序就错了,还有就是最后一个是取模为零的时候也会出问题。想了很久才想到这个问题,改正之后终于过了。以后写程序要仔细,不能想当然啊。
附PKU 2356代码:
#include <cstdio>
const int N = 10010;

int main()
{
    
int a[N], n, mod[N] = {0}, tmp = 0, len = 0, pos;

    scanf(
"%d"&n);
    
for (int i = 1; i <= n; i++)
    {
        scanf(
"%d"&a[i]);
        
if (len)    continue;
        tmp 
= (tmp + a[i]) % n;
        
if (tmp == 0)
        {
            len 
= i;
            pos 
= 1;
        }
        
if (mod[tmp])
        {
            len 
= i - mod[tmp];
            pos 
= mod[tmp] + 1;
        }
        
else
            mod[tmp] 
= i;
    }
    printf(
"%d\n", len);
    
for (int i = 0; i < len; i++)
        printf(
"%d\n", a[pos+i]);

    
return 0;
}
posted on 2009-06-12 09:09 sdfond 阅读(511) 评论(2)  编辑 收藏 引用 所属分类: Algorithm - Combinatorics

FeedBack:
# re: 抽屉原理 - PKU 3370 & PKU 2356 2010-08-20 14:39 Adrian
抽屉定理解的不是整除吗,两组人的年龄和相等怎么用抽屉定理解呢?不太清楚哎!请教,(*^__^*) 嘻嘻……  回复  更多评论
  
# re: 抽屉原理 - PKU 3370 & PKU 2356 2010-08-21 09:02 sdfond
@Adrian
抽屉原理的含义你到网上查查~
n个人如果都取最大值的话,n个人的年龄之和是n * k,因此年龄取值范围是1到n * k。而从n个人选出任意多个人的选法有2 ^ n种,选出来的这些人年龄范围肯定也在1到n * k之间。把年龄取值范围当做抽屉,如果2 ^ n > n * k那么一定存在2组人年龄和相等。  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理