1.排列:全排列n!
使用next_permutation函数
1 输出序列{1,2,3,4}字典序的全排列。 2 #include <iostream> 3 #include<algorithm> 4 using namespace std; 5 6 int main(int argc, char** argv) { 7 int a[4]={1,2,3,4}; 8 sort(a,a+4); 9 do{ 10 //cout<<a[0]<<" "<<a[1]<<" "<<a[2]<<" "<<a[3]<<endl; 11 for(int i=0;i<4;i++) 12 cout<<a[i]<<" "; 13 cout<<endl; 14 }while(next_permutation(a,a+4)); 15 return 0; 16 }
输入任意一个字符串,输出其字典序的全排列
1 #include <iostream> 2 #include<algorithm> 3 using namespace std; 4 5 int main(int argc, char** argv) { 6 string str; 7 cin>>str; 8 sort(str.begin(),str.end()); 9 do{ 10 cout<<str<<endl; 11 }while(next_permutation(str.begin(),str.end())); 12 return 0; 13 }
递归法
设一组数p = {r1, r2, r3, … ,rn}, 全排列为perm(p),pn = p – {rn}。则perm(p) = r1perm(p1), r2perm(p2), r3perm(p3), … , rnperm(pn)。当n = 1时perm(p} = r1。
如:求{1, 2, 3, 4, 5}的全排列
1、首先看最后两个数4, 5。 它们的全排列为4 5和5 4, 即以4开头的5的全排列和以5开头的4的全排列。
由于一个数的全排列就是其本身,从而得到以上结果。
2、再看后三个数3, 4, 5。它们的全排列为3 4 5、3 5 4、 4 3 5、 4 5 3、 5 3 4、 5 4 3 六组数。
即以3开头的和4,5的全排列的组合、以4开头的和3,5的全排列的组合和以5开头的和3,4的全排列的组合.
1 #include < 2 iostream> 3 using namespace std; 4 5 void Perm(int start, int end, int a[]) { 6 //得到全排列的一种情况,输出结果 7 if (start == end) { 8 for (int i = 0; i < end; i++) 9 cout << a[i] << ' '; 10 cout << endl; 11 return; 12 } 13 for (int i = start; i < end; i++) { 14 swap(a[start], a[i]); //交换 15 Perm(start + 1, end, a); //分解为子问题a[start+1,...,end-1]的全排列 16 swap(a[i], a[start]); //回溯 17 } 18 } 19 int main() { 20 int i, n, a[10]; 21 while (cin >> n, n) { 22 for (i = 0; i < n; i++) 23 { 24 a[i] = i + 1; 25 } 26 Perm(0, n, a); 27 } 28 return 0; 29 }
2.组合:C(n,k),n个数中任取k个数
递归法
实际上就是在n个数中,标记k个数,然后输出这k个数的过程。使用一个visited数组来记录相应下标的数是否被选中。
1 #include <iostream> 2 using namespace std; 3 4 void dfs(int pos, int cnt, int n, int k, int a[],bool visited[]) { 5 //已标记了k个数,输出结果 6 if (cnt == k) { 7 for (int i = 0; i < n; i++) 8 if (visited[i]) cout << a[i] << ' '; 9 cout << endl; 10 return; 11 } 12 13 //处理到最后一个数,直接返回 14 if (pos == n) return; 15 16 //如果a[pos]没有被选中 17 if (!visited[pos]) { 18 //选中a[pos] 19 visited[pos] = true; 20 //处理在子串a[pos+1, n-1]中取出k-1个数的子问题 21 dfs(pos + 1, cnt + 1, n, k, a,visited); 22 //回溯 23 visited[pos] = false; 24 } 25 //处理在子串a[pos+1, n-1]中取出k个数的问题 26 dfs(pos + 1, cnt, n, k, a, visited); 27 } 28 int main() { 29 int i, n, k; 30 while (cin >> n >> k, n || k) 31 { 32 int *a = new int[n]; 33 bool *visited = new bool[n]; 34 for (i = 0; i < n; i++) 35 { 36 a[i] = i + 1; 37 visited[i] = false; 38 } 39 dfs(0, 0, n, k, a, visited); 40 delete[] a; 41 delete[] visited; 42 } 43 getchar(); 44 return 0; 45 }
‘01’转换法
本程序的思路是开一个数组,其下标表示1到n个数,数组元素的值为1表示其代表的数被选中,为0则没选中。
首先初始化,将数组前n个元素置1,表示第一个组合为前n个数。
然后从左到右扫描数组元素值的“10”组合,找到第一个“10”组合后将其变为“01”组合,同时将其左边的所有“1”全部移动到数组的最左端。
当第一个“1”移动到数组的n-m的位置,即n个“1”全部移动到最右端时,就得到了最后一个组合。
例如求5中选3的组合:
1 1 1 0 0 //1,2,3
1 1 0 1 0 //1,2,4
1 0 1 1 0 //1,3,4
0 1 1 1 0 //2,3,4
1 1 0 0 1 //1,2,5
1 0 1 0 1 //1,3,5
0 1 1 0 1 //2,3,5
1 0 0 1 1 //1,4,5
0 1 0 1 1 //2,4,5
0 0 1 1 1 //3,4,5
1 #include <iostream> 2 using namespace std; 3 4 //输出结果 5 void printRes(int* a, bool* index, int n) 6 { 7 for (int i=0;i<n;i++) 8 { 9 if (index[i]) 10 { 11 cout << a[i] << " "; 12 } 13 } 14 cout << endl; 15 } 16 17 //检查最后k个位置是否已全变成0 18 bool hasDone(bool* index, int n, int k) 19 { 20 for (int i=n-1;i>=n-k;i--) 21 { 22 if (!index[i]) 23 { 24 return false; 25 } 26 } 27 return true; 28 } 29 30 void Comb(int* a, int n, int k) 31 { 32 bool *index = new bool[n](); 33 //选中前k个位置 34 for (int i = 0; i < k; i++) 35 { 36 index[i] = true; 37 } 38 printRes(a, index, n); 39 40 while (!hasDone(index, n, k)) 41 { 42 //从左到右扫描数组 43 for (int i = 0; i < n - 1; i++) 44 { 45 //找到第一个“10”组合将其变成"01"组合 46 if (index[i] && !index[i + 1]) 47 { 48 index[i] = false; 49 index[i + 1] = true; 50 51 //将"01"组合左边的1移到最左边 52 int count = 0; 53 for (int j = 0; j < i; j++) 54 { 55 if (index[j]) 56 { 57 index[j] = false; 58 index[count++] = true; 59 } 60 } 61 printRes(a, index, n); 62 break; 63 } 64 } 65 } 66 delete[] index; 67 } 68 int main() 69 { 70 int n,k; 71 while (cin>>n>>k) 72 { 73 int *a = new int[n](); 74 for (int i = 0; i < n; i++) 75 { 76 a[i] = i+1; 77 } 78 Comb(a, n, k); 79 delete[] a; 80 } 81 82 return 0; 83 }