天天看點

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

本文章讨論的是将一個包含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("\n");
 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("\n");
 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 }      

繼續閱讀