[C++] 递归之全排列问题、半数集
一、递归的定义
一个过程或函数在其定义或说明中又直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个原问题相似的规模较小的问题来求解。
二、用递归求解问题的主要步骤
1、找出相似性
2、定义出口
三、递归实例
1、全排列问题
例如:
list[3] = {1,2,3}。
则全排列结果为:{1,2,3},{1,3,2},{2,1,3},{2,3,1},{3,2,1},{3,1,2}。
1 #include<iostream> 2 using namespace std; 3 4 void Perm(int list[], int k, int m); 5 void Swap(int &a, int &b); 6 7 void Perm(int list[], int k, int m) 8 {//产生list[k:m]的所有排列 9 if(k == m) 10 { //只剩下1个元素 11 for(int i = 0; i <= m; i++) 12 cout<< list[i]; 13 cout<<endl; 14 } 15 else //还有多个元素待排列,递归产生排列 16 for(int i = k; i <= m; i++) 17 { 18 Swap(list[k], list[i]); 19 Perm(list, k+1, m); 20 Swap(list[k], list[i]); 21 } 22 } 23 24 void Swap(int &a, int &b) 25 { 26 int temp = a; a = b; b = temp; 27 } 28 29 int main() 30 { 31 int list[3] = {1,2,3}; 32 Perm(list, 0, 2); 33 return 0; 34 }
2、重复元素全排列
例如:
list[4] = {1,1,2,2}。
则重复元素全排列结果为:{1,1,2,2},{1,2,1,2},{1,2,2,1},{2,1,1,2},{2,1,2,1},{2,2,1,1}。
1 #include<iostream> 2 using namespace std; 3 4 void Perm(int list[], int k, int m); 5 void Swap(int &a, int &b); 6 bool ok(int list[], int k, int i); 7 8 void Perm(int list[], int k, int m) 9 {//产生list[k:m]的所有排列 10 if(k == m) 11 { //只剩下1个元素 12 for(int i = 0; i <= m; i++) 13 cout<< list[i]; 14 cout<<endl; 15 } 16 else //还有多个元素待排列,递归产生排列 17 for(int i = k; i <= m; i++) 18 { //若不重复则执行 19 if(ok(list, k, i)) 20 { 21 Swap(list[k], list[i]); 22 Perm(list, k+1, m); 23 Swap(list[k], list[i]); 24 } 25 } 26 } 27 28 void Swap(int &a, int &b) 29 { 30 int temp = a; a = b; b = temp; 31 } 32 33 //判断元素[k..i-1]与i是否重复 34 bool ok(int list[], int k, int i) 35 { 36 if(i > k) 37 { 38 for(int t = k; t < i; t++) 39 { 40 if(list[t] == list[i]) 41 return false; 42 } 43 } 44 else 45 return true; 46 } 47 48 int main() 49 { 50 int list[4] = {1,1,2,2}; 51 Perm(list, 0, 3); 52 return 0; 53 }
3、半数集
在自然数 n 的左边加上一个自然数,但该自然数不能超过最近添加的数的一半。
set(6) = {6,16,26,126,36,136},半数集 set(n) 的元素个数。
1 #include<iostream> 2 using namespace std; 3 4 //递归算法 5 int comp(int n) 6 { 7 int ans = 1; 8 if(n > 1) 9 { 10 for(int i = 1; i <= n/2; i++) 11 ans += comp(i); 12 } 13 return ans; 14 } 15 16 /* 17 记忆式搜索方法 18 该方法用数组 a 来记录已经算过的半数集元素个数, 19 当输入的n在之前计算过时,则直接输出a[n]即可 20 */ 21 int a[1001]; 22 int comp2(int n) 23 { 24 int ans = 1; 25 if(a[n] > 0) 26 return a[n]; 27 28 for(int i = 1; i <= n/2; i++) 29 ans += comp2(i); 30 a[n] = ans; 31 return ans; 32 } 33 34 int main() 35 { 36 int n; 37 cin>> n; 38 int ans = comp(n); 39 cout<< ans <<endl; 40 41 int ans2 = comp2(n); 42 cout<< ans2 <<endl; 43 return 0; 44 }