问题描述:列出给定集合的所有子集合,包括空子集。
思路:一个集合的所有子集合的个数是个(n是集合中元素的个数),而一个位数为n的二进制也可以表示
个数,所以,只要产生出了所有二进制数,就可以列出所有的子集了。在二进制的求解中,先来看这样一个例子。
11111 01111
+ 1
--------------------
11111 10000
当这个数加1时,如果当前位是1,那么当前位就变成0并且向前进1位;接着前一位如果是1,也会变成0并且继续进位;以此类推,直到遇到当前位是0的情况,就变成1,然后整个加法就完成了。依照此思路,很容易写出代码。
- #include <stdio.h>
- #include <math.h>
- #define MAX 1000
-
- int n=4;// the number of the set elements
- int set[MAX]={1,2,3,4};
- int path[MAX]={0};
- int count=1;
-
- //prototype
- void print_set();
-
- int main()
- {
- int sum=(int)pow(2.0,n)-1;
- int index,index_re;
- printf("%d:{}\n",count);
- for(index=0;index<sum;index++)
- {
- for(index_re=n-1;index_re>=0;index_re--)
- {
- if(path[index_re]==1)
- path[index_re]=0;
- else
- {
- path[index_re]=1;
- break;
- }
- }
- count++;
- printf("%d:{",count);
- print_set();
- }
- return 0;
- }
-
- void print_set()
- {
- int index;
- for(index=0;index<n;index++)
- {
- if(path[index]!=0)
- printf("%d ",set[index]);
- }
- printf("}\n");
- }
参考资料:《C语言名题精选百则技巧篇》
列出所有子集-----字典顺序
问题描述:写一个程序,用字典顺序把一个集合的所有子集找出来。
此题的思路来自《C语言名题精选百则技巧篇》:字典顺序,也就是字符串比较时的顺序规则。可以采取这样的思路
先定义n是集合的个数并且集合是已经从小到大排好顺序的{1,2,3....n}的集合。集合从{1}开始(此时下标index=0),
1.当state[i]<n时,就向右进行扩展,将state[2]=2;接着将state[3]=3;
2.当state[index]==n时,就不能向右边进行扩展了,此时就需要向左边处理了。此时的集合是{1,2,3,....,n-2,n-1,n},那么,要找比这个集合刚好大一点的,就是{1,2,3,....n-2,n},所以就可以归纳出规则为:将index减1并且将state[index]加1。
3.如果state[0]==n,那么循环就结束,反之则重复第1,2步,直到state[0]==n。
代码如下:
1 #include <stdio.h> 2 #define MAX 1000 3 4 int main() 5 { 6 int n=3; 7 int set[MAX]={1}; 8 int index=0; 9 int count=2; 10 printf("1:{}\n2:{1}\n"); 11 while(set[0]!=n) 12 { 13 if(set[index]<n) 14 { 15 set[index+1]=set[index]+1; 16 index++; 17 } 18 else 19 { 20 index--; 21 set[index]++; 22 } 23 int a_index; 24 count++; 25 printf("%d:{",count); 26 for(a_index=0;a_index<=index;a_index++) 27 printf("%d ",set[a_index]); 28 printf("}\n"); 29 } 30 return 0; 31 }
12345
1235
124
1245
125
13
134
1345
135
14
145
15
2 子集不是全排列
参考资料:《C语言名题精选百则技巧篇》
产生全排列问题
- //全排列的递归实现
- #include <stdio.h>
- #include <string.h>
- void Swap(char *a, char *b)
- {
- char t = *a;
- *a = *b;
- *b = t;
- }
- //k表示当前选取到第几个数,m表示共有多少数.
- void AllRange(char *pszStr, int k, int m)
- {
- if (k == m)
- {
- static int s_i = 1;
- printf(" 第%3d个排列\t%s\n", s_i++, pszStr);
- }
- else
- {
- for (int i = k; i <= m; i++) //第i个数分别与它后面的数字交换就能得到新的排列
- {
- Swap(pszStr + k, pszStr + i);
- AllRange(pszStr, k + 1, m);
- Swap(pszStr + k, pszStr + i);
- }
- }
- }
- void Foo(char *pszStr)
- {
- AllRange(pszStr, 0, strlen(pszStr) - 1);
- }
- int main()
- {
- printf(" 全排列的递归实现\n");
- printf(" --by MoreWindows( http://blog.csdn.net/MoreWindows )--\n\n");
- char szTextStr[] = "123";
- printf("%s的全排列如下:\n", szTextStr);
- Foo(szTextStr);
- return 0;
产生全排列——字典顺序
- #include <stdio.h>
- #include <stdlib.h>
- #define LOOP 1
- #define SWAP(a,b) { int t; t = a; a = b; b = t; }
- #define REVERSE(a,b) { int i, j; \
- for (i=(a), j=(b); i < j; i++, j--) \
- SWAP(perm[i], perm[j]); \
- }
- #define DISPLAY(n) { int i; \
- printf("\n"); \
- for (i = 0; i < n; i++) \
- printf("%d ", perm[i]); \
- }
- void again(int perm[], int L, int R)
- {
- int i = R;
- while (LOOP) {
- if (R - L + 1 > 2) {
- again(perm, L+1, R);
- DISPLAY(R);
- }
- if (i > L ) {
- SWAP(perm[L], perm[i]);
- REVERSE(L+1, R);
- DISPLAY(R);
- i--;
- }
- else
- break;
- }
- }
- void permut(int perm[], int n)
- {
- int i;
- for (i = 0; i < n; i++)
- perm[i] = i + 1;
- again(perm, 0, n-1);
- }
- #define MAXSIZE 20
- void main(void)
- {
- int perm[MAXSIZE];
- char line[100];
- int n;
- gets(line);
- n = atoi(line);
- permut(perm, n);
- }