zoukankan      html  css  js  c++  java
  • 高效生成集合的固定子集划分

    本文章讨论的是将一个包含n个不同元素的集合分割为所有的s个不为空的集合,且每次生成的s个集合不需要考虑顺序关系。相关的背景内容在我的倒数第四篇博客中已经说了,这篇文章主要是贴代码。

      1 #include <stdio.h>
      2 #include <malloc.h>
      3 #define SET 6
      4 #define PART 3
      5 //这里我们执行的时候用先进先出队列来模拟整个的生成情况
      6 struct set_par_link
      7 {
      8     int* new_set;//代表当前的生成的集合划分
      9     struct set_par_link* next_set_par;//代表的是另外的一个集合划分
     10 };
     11 struct set_par_link* set_par_link_head=NULL;
     12 struct set_par_link* set_par_link_rear=NULL;
     13 int* standard_set_par;//代表的是初始的集合划分
     14 //这两个是整个链表的头部与尾部,用来插入与删除,初始化为空.
     15 void output(int* new_set)//输出函数,给定开始地址。
     16 {
     17     int for_i,for_j;
     18     for (for_i = 0; for_i < SET; for_i++)
     19     {
     20         printf("%d ", new_set[for_i]);
     21     }
     22     printf("
    ");
     23     for(for_i=1;for_i<=PART;for_i++)
     24     {
     25         printf("(");
     26         for (for_j = 0; for_j < SET; for_j++)
     27         {
     28             if (new_set[for_j] == for_i)
     29             {
     30                 printf("%d ", for_j+1);
     31             }
     32         }
     33         printf(")  ");
     34     }
     35     printf("
    ");
     36 }
     37 void insert_new_set_par(int* new_set_par)
     38 {
     39     struct set_par_link* new_set_par_link;
     40     new_set_par_link = (struct set_par_link*)malloc(sizeof(struct set_par_link));
     41     new_set_par_link->new_set = new_set_par;
     42     new_set_par_link->next_set_par = NULL;
     43     if (set_par_link_head == NULL)
     44     {
     45         set_par_link_head = set_par_link_rear = new_set_par_link;
     46     }
     47     else
     48     {
     49         set_par_link_rear->next_set_par = new_set_par_link;
     50         set_par_link_rear = new_set_par_link;
     51     }
     52 }
     53 int type_one(int* father_set_par)//对当前的集合划分做第一种操作的逆操作
     54 {
     55     int for_i,reverse,equal;//equal是用来记录第一个相等的对,reverse是用来记录第一个逆序的对
     56     int* new_set_par;
     57     new_set_par = (int*) malloc(sizeof(int) *SET);
     58     for (for_i = 0; for_i < SET; for_i++)
     59     {
     60         new_set_par[for_i] = father_set_par[for_i];
     61     }
     62     for_i=SET-2;
     63     equal=reverse=-1;
     64     while(for_i>=0)
     65     {
     66         if(new_set_par[for_i+1]<new_set_par[for_i])//当发现逆序时
     67         {
     68             if(reverse!=-1)//如果已经发现了逆序的对,则当前序列不可能是子序列根据一型操作生成的
     69             {
     70                 free(new_set_par);
     71                 return 0;//所以直接返回
     72             }
     73             else
     74             {
     75                 if(equal!=-1)//如果已经发现了相等的对,则当前序列也不可能通过一型操作生成
     76                 {
     77                     free(new_set_par);
     78                     return 0;//直接返回
     79                 }
     80                 else//否则,记录下当前的逆序索引
     81                 {
     82                     reverse=for_i;
     83                 }
     84             }
     85         }
     86         else//当不是逆序时
     87         {
     88             if(new_set_par[for_i+1]==new_set_par[for_i])//如果发现的是相等的对
     89             {
     90                 if(equal==-1)//如果之前木有发现相等的对
     91                 {
     92                     equal=for_i;//则直接赋值
     93                 }
     94                 //这样我们就记录了从右到左的第一个相等的对
     95             }
     96         }
     97         for_i--;//遍历
     98     }
     99     if(reverse==-1)//最后如果逆序对不存在
    100     {
    101         if (equal != SET - 2)
    102         {
    103             new_set_par[equal + 1]++;//直接对相等的那个对后面的那个数加一
    104         }
    105         else//如果最后一对是相等的,则不可能是通过第一个操作生成的
    106         {
    107             free(new_set_par);
    108             return 0;
    109         }
    110     }
    111     else//如果逆序对存在
    112     {
    113         if(new_set_par[reverse+1]+1<new_set_par[reverse])//如果这个逆序的差值大于1,则不可能由一型操作生成
    114         {
    115             free(new_set_par);
    116             return 0;
    117         }
    118         else//如果相差刚好为1,我们还需要考虑后面的那个数是否比逆序对后面的那个数刚好大一
    119         {
    120             if (new_set_par[reverse + 2] == new_set_par[reverse])
    121             {
    122                 new_set_par[reverse + 1]++;
    123             }
    124             else
    125             {
    126                 free(new_set_par);
    127                 return 0;
    128             }
    129         }
    130     }
    131     insert_new_set_par(new_set_par);
    132     return 1;
    133 }
    134 int type_two(int* father_set_par)
    135 {
    136     int for_i,temp,for_j,for_k,for_m;
    137     int* new_set_par;
    138     int* second_new_set_par;
    139     new_set_par = (int*) malloc(sizeof(int) *SET);
    140     for (for_i = 0; for_i < SET; for_i++)
    141     {
    142         new_set_par[for_i] = father_set_par[for_i];
    143     }
    144     for_i = SET - 2;
    145     while( (new_set_par[for_i] <=new_set_par[for_i + 1])&&for_i>=0)//寻找从右边开始的第一个逆序对
    146     {
    147         for_i--;
    148     }//这里由限制生长的性质,从右数第一个逆序对不可能是开头的第一个对
    149     //下面来讨论的是第二个操作没有生成新逆序对的情况
    150     //我们需要扫描每一个在for_i右边的增序对,并考虑他的可行性
    151     for_j = SET - 2;
    152     while (for_j > for_i)//遍历
    153     {
    154         if (new_set_par[for_j] < new_set_par[for_j + 1])//增序对
    155         {
    156             for_k = for_j - 1;
    157             while( (new_set_par[for_k] < new_set_par[for_j])&&for_k>=0)
    158             {
    159                 for_k--;
    160             }
    161             if (for_k != -1)//如果当前值并不比前面所有的值都大,则交换之后遵守k限制增长规则
    162             {
    163                 second_new_set_par = (int*) malloc(sizeof(int) *SET);//这里我们要建立副本,因为可能会有多个
    164                 for (for_m = 0; for_m < SET; for_m++)
    165                 {
    166                     second_new_set_par[for_m] = new_set_par[for_m];
    167                 }
    168                 //然后进行调换
    169                 temp = second_new_set_par[for_j + 1];
    170                 second_new_set_par[for_j + 1] = second_new_set_par[for_j];
    171                 second_new_set_par[for_j] = temp;
    172                 insert_new_set_par(second_new_set_par);
    173             }
    174             else//如果当前值比之前的都大,都不可能是通过第二种操作生成的。例子,11123不可以由11132生成,因为
    175                 //后者违反了k生长的规则
    176             {
    177                 //do nothing
    178             }//其实这里的判断可以合并起来
    179         }
    180         else
    181         {
    182             //do nothing
    183         }
    184         for_j--;
    185     }
    186     if (for_i != -1)//此时对应的是生成的父节点有逆序对的情况
    187     {
    188         if (new_set_par[for_i - 1] <= new_set_par[for_i + 1])//对应的是二型操作生成了新逆序对的情况
    189         {
    190             for_k = for_j - 2;
    191             while (for_k >= 0 && (new_set_par[for_k] < new_set_par[for_j - 1]))
    192             {
    193                 for_k--;
    194             }//同样需要考虑当前值和前一个值都是第一次出现的情况,这种情况下是不合法的
    195             if (for_k == -1)//例子11232不可以由11322生成,因为后者不是k限制生长的。
    196             {
    197                 free(new_set_par);
    198                 return 0;
    199             }
    200             second_new_set_par = (int*) malloc(sizeof(int) *SET);//这里我们要建立副本,因为可能会有多个
    201             for (for_m = 0; for_m < SET; for_m++)
    202             {
    203                 second_new_set_par[for_m] = new_set_par[for_m];
    204             }
    205             //然后进行调换
    206             temp = second_new_set_par[for_i - 1];
    207             second_new_set_par[for_i  -1] = second_new_set_par[for_i];
    208             second_new_set_par[for_i] = temp;
    209             insert_new_set_par(second_new_set_par);
    210         }//逆向操作交换一下就可以了
    211         else
    212         {
    213             //do nothing
    214         }
    215     }
    216     else
    217     {
    218         //do nothing 因为其他的留给下面的过程去考虑
    219     }
    220     free(new_set_par);
    221     return 0;
    222 }
    223 
    224 
    225 int main()
    226 {
    227     int for_i,for_j;
    228     struct set_par_link* temp_set_par_link;
    229     standard_set_par = (int*) malloc(sizeof(int) *SET);
    230     for(for_i=0;for_i<SET-PART;for_i++)
    231     {
    232         standard_set_par[for_i]=1;
    233     }
    234     for(for_j=1;for_j<=PART;for_j++)
    235     {
    236         standard_set_par[for_i+for_j-1]=for_j;
    237     }
    238     insert_new_set_par(standard_set_par);//插入第一个节点,即头节点
    239     while (set_par_link_head != NULL)//然后开始进行层序遍历
    240     {
    241         type_two(set_par_link_head->new_set);
    242         type_one(set_par_link_head->new_set);
    243         temp_set_par_link = set_par_link_head->next_set_par;
    244         output(set_par_link_head->new_set);
    245         free(set_par_link_head->new_set);
    246         free(set_par_link_head);
    247         set_par_link_head = temp_set_par_link;
    248     }
    249 }
  • 相关阅读:
    四则运算结对作业
    读《构建之法》第四、十七章有感
    四则运算练习的命令行软件
    Spring01
    oop01
    运行shell脚本的三种方式
    正则表达式的基础组成部分
    C语言文件函数
    shell文件描述符及重定向
    shell基础
  • 原文地址:https://www.cnblogs.com/huangfeidian/p/3451992.html
Copyright © 2011-2022 走看看