zoukankan      html  css  js  c++  java
  • 集合的所有分割方式2013年1月28日

           问题描述:分割集合成多个子集合,这几个子集合间没有交集且他们的并集是原集合。

           思路:将包含n个元素的集合set的分割表示为n个数字。比如set[]={1,2,3,4},那么{1,2},{3,4}就可以表示为1122,这4个数分别表示set[0]在第一个分割集合,set[1]在第一个分割集合,set[2]在第二个分割集合,set[3]在第二个分割集合。将这个过程称为编码。

           然后抓住两个要点:

           1.第i个元素的编码一定小于或者等于i。约定一下,set原集合已经从小到大排列好,分割的集合也是这样排好。然后,很容易理解,第1个元素的编码肯定为1。接着,第2个元素如果在第一个分割集合中,那么他的编码也是1;但如果不是在第一个分割集合中,那么第2个元素的编码肯定是2,因为在第二个分割集合中,最小的数最少也是2;依次类推,可以很容易用数学归纳法证明。

           2.第i个元素的编码一定小于等于1,2,3,....i-1这些元素的编码中的最大值再加1。这也很容易想到,也很容易用数学归纳法证明。

           抓住这个要点后,就用深度搜索构造一颗子集合树就可以解决问题了。但是,我在构造子集树的过程中出现了一个思维上的错误,导致浪费了不少调试的时间。具体的错误见代码注释的描述。

           代码如下:

     1 #include <stdio.h>
     2 #define MAX 1000
     3 
     4 int set[MAX]={1,2,3,4};
     5 int n=4;
     6 int code[MAX]={1,1,1,1};
     7 
     8 //prototype
     9 void DFS(int index);
    10 
    11 void print_set()
    12 {
    13     int index;
    14     int max=-1;
    15     printf("{");
    16     for(index=0;index<n;index++)
    17     {
    18         if(code[index]==1) 
    19             printf("%d ",set[index]);
    20         if(max<code[index])
    21             max=code[index];
    22     }
    23     printf("},{");
    24     for(index=2;index<=max;index++)
    25     {
    26         int index_2; 
    27         for(index_2=0;index_2<n;index_2++)
    28             if(code[index_2]==index)
    29                 printf("%d ",set[index_2]);
    30         printf("},{");
    31     }
    32     printf("\n");
    33 }
    34 
    35 //find out the max code of 1,2,3...i-1 and plus 1
    36 int max_pre(int i)
    37 {
    38     int index;
    39     int max=-1;
    40     for(index=0;index<i;index++)
    41         if(code[index]>max)
    42             max=code[index];
    43     return (max+1); 
    44 }
    45 
    46 int main()
    47 {
    48     int i; 
    49     DFS(1);
    50     return 0;
    51 }
    52 
    53 void DFS(int index)
    54 {
    55     print_set();
    56     if(index==n)
    57         return ;
    58     for(;index<n;index++)
    59     {  
    60         int temp=code[index]+1;
    61         //在写这里的代码时,我出现了一个思维上的误区:在回溯时我只顾把code[index]++,而没有将code[index]在2到max_pre(index)遍历,这导致了我调试了挺长时间。
    62         for(;temp<=index+1 && temp<=max_pre(index);temp++)
    63         {
    64             int save=code[index];
    65             code[index]=temp;
    66             DFS(index+1);
    67             code[index]=save;
    68         }
    69 
    70     }
    71 
    72 }

           参考资料:《C语言名题精选百则技巧篇》

           如果你觉得我的文章对你有帮助,请推荐一下,非常感谢!

  • 相关阅读:
    LightOJ 1132 Summing up Powers(矩阵快速幂)
    hdu 3804 Query on a tree (树链剖分+线段树)
    LightOJ 1052 String Growth && uva 12045 Fun with Strings (矩阵快速幂)
    uva 12304 2D Geometry 110 in 1! (Geometry)
    LA 3263 That Nice Euler Circuit (2D Geometry)
    2013 SCAUCPC Summary
    poj 3321 Apple Tree (Binary Index Tree)
    uva 11796 Dog Distance (几何+模拟)
    uva 11178 Morley's Theorem (2D Geometry)
    动手动脑
  • 原文地址:https://www.cnblogs.com/NeilHappy/p/2879725.html
Copyright © 2011-2022 走看看