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语言名题精选百则技巧篇》

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

  • 相关阅读:
    layui动态修改select的选中项
    ES6数组新增方法
    A Realtime BigData Dashboad
    Spark Streaming
    使用Converter实现控件的动态显隐
    Mysql 使用mysqldump进行备份与还原
    大型Java进阶专题(六) 设计模式之代理模式
    HTML开发之--marquee标签
    iOS开发之--instancetype和id
    请求处理常见tag语法
  • 原文地址:https://www.cnblogs.com/NeilHappy/p/2879725.html
Copyright © 2011-2022 走看看