高效生成集合的固定子集划分

本文章讨论的是将一个包含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 }
原文地址:https://www.cnblogs.com/huangfeidian/p/3451992.html