排列组合(两种方法)
来源:互联网 发布:网络销售是做什么的 编辑:程序博客网 时间:2024/05/17 17:58
排列组合是组合数学的基础,从n个不同元素中任取m个,约定1<m≤n,按任意一种次序排成一列,称为排列,其排列种数记为(Arrange)A(n,m)。从n个不同元素中任取m个(约定1<m<n)成一组,称为一个组合,其组合种数记为C(n,m)。计算A(n,m)与C(n,m)只要简单进行乘运算即可,要具体展现出排列的每一列与组合的每一组,决非轻而易举。
注意:
1、 排列A有序 A(n,m) = n * (n-1) * …*(n-m+1)
2、 组合C无序 C(n,m) = A(n,m) / A(m,m)
3、 注意到组合与组成元素的顺序无关,约定组合中的组成元素按递增排序。因而,把以上程序中的约束条件作简单修改: a[i]==a[j] 修改为 a[i]>=a[j]
有两种方法:
1、DFS方法适用于不重复的情况下,分治法可适用于有元素相同的情况下
2:分治法元素相同时的情况为:
//1、arr[i]!=arr[k],因为这样交换后剩下的元素是一样的,两种全排列是重复的
//2、arr[k+1]—>arr[i-1],也就是k和i之间的元素不能和arr[i]相等,因为k和i之间的元素都是和k交换过的,
//如果arr[i]和arr[k+1]—>arr[i-1]之间的元素有相等的,那么这两种排列也是重复的
//下面代码中||运算前的是第一种情况,或运算之后的是第二种情况
排列:DFS方法一:回溯法(全排列的数组中不可以有重复的元素)/*1-n中m个数的全排列*/#include <iostream>#include <vector>using namespace std;int count = 0;vector<int> v;bool Single(int num){ for (int i=0; i<v.size(); ++i) { if (v[i] == num) return false; } return true;}//全排列void perm(int n, int m){ if (m == 0) { ++count; return; } for (int i=1; i<=n; ++i) { if (Single(i)) { v.push_back(i); perm(n, m-1); v.pop_back(); } }}int main(){ int n, m; cin >> n >> m; perm(n, m); cout << count << endl; return 0;}
回溯法:组合(组合的数组中不可以有重复的元素)/*1-n中m个数的组合*/#include <iostream>#include <vector>using namespace std;int count = 0;vector<int> v;bool Single(int num){ for (int i=0; i<v.size(); ++i) { if (v[i] == num) return false; } return true;}//组合void perm(int n, int m){ if (m == 0) { ++count; return; } for (int i=1; i<=n; ++i) { if (Single(i)) { v.push_back(i); perm(n, m-1); v.pop_back(); } }}int main(){ int n, m; cin >> n >> m; perm(n, m); cout << count << endl; return 0;}
全排列方法二:分治法(数组中可以有重复元素,下一个程序就是怎样消除重复)#include <iostream>using namespace std;int count = 0;void swap(int* arr, int i, int j){ arr[i] = arr[i] ^ arr[j]; arr[j] = arr[i] ^ arr[j]; arr[i] = arr[i] ^ arr[j]; }void perm(int* arr, int len, int m, int n){ //生成了一种全排列 if (m == n) { ++count; return; } for (int i=m; i<=n; ++i) { swap(arr, m, i); perm(arr, len, m+1, n); swap(arr, m, i); }}int main(){ int arr[9]; for (int i=0; i<9; ++i) { arr[i] = i+1; } perm(arr, 9, 0, 8); cout << count << endl; return 0;}
分治法:全排列(数组中可以有重复的元素ADCD)#include <iostream>#include <string>using namespace std;string str;string* pwd;int n;int count = 0;void swap(int index, int i, int j){ char tmp = pwd[index][i]; pwd[index][i] = pwd[index][j]; pwd[index][j] = tmp; }//判断是否重复出现//一般的全排列算法只能排列数组中没有重复的数字或字母//但是如果出现重复的情况下比如aaaabbbb进行全排列,好多排列虽然看似不重复,但是结果是重复的//这种方法进行全排列时(分治法),从1-n个元素中选n次,每次选1个之前不同的数,然后对剩下的数进行全排列//也就是perm(R)=(r1)perm(R1),(r2)perm(R2),(r3)pwem(R3)....(rn)perm(Rn)//每次i和k交换的时候,重点是://1、arr[i]!=arr[k],因为这样交换后剩下的元素是一样的,两种全排列是重复的//2、arr[k+1]--->arr[i-1],也就是k和i之间的元素不能和arr[i]相等,因为k和i之间的元素都是和k交换过的,//如果arr[i]和arr[k+1]--->arr[i-1]之间的元素有相等的,那么这两种排列也是重复的//下面代码中||运算前的是第一种情况,或运算之后的是第二种情况 bool Appear(int index, char target, int begin, int end){ for (int i=begin; i<=end; ++i) { if (target == pwd[index][i]) return true; } return false;}void perm(int index, int k, int m){ //得到一种全排列 if (k == m) { //判断在不在str中 if (str.find(pwd[index]) != -1) { ++count; } return; } //全排列 for (int i=k; i<=m; ++i) { //判断字母是否重复 if ((i!=k && pwd[index][i]==pwd[index][k]) || Appear(index, pwd[index][i], k+1, i-1)) continue; swap(index, k, i); perm(index, k+1, m); swap(index, k, i); }}int main(){ cin >> str; cin >> n; pwd = new string[n]; for (int i=0; i<n; ++i) cin >> pwd[i]; for (int i=0; i<n; ++i) { perm(i, 0, 7); } cout << count << endl; delete[] pwd; return 0;}
0 0
- 排列组合(两种方法)
- Python.排列组合实现方法
- 【排列组合】有序进行全排列的几种方法
- 列出排列组合2^n种可能的方法
- 两元素交换的排列组合问题
- 两种keyboardinput方法
- 模式识别两种方法
- 两种方法求丑数
- 缩略图两种方法
- 两种封装方法
- LCA两种方法
- POJ1703 两种方法
- 两种删除方法
- 排列组合
- 排列组合
- 排列组合
- 排列组合
- 排列组合
- Android--第一行代码 Intent用法
- 未来科技 HoloLens演示3D地理信息系统
- codis搭建部署实验
- android UI——绘制加减号按钮
- mac 上代码托管到svn和github
- 排列组合(两种方法)
- uva10304(二维完全背包DP)
- 2016百度之星
- 跟着郝斌学数据结构(06)——队列(链式队列)
- 为什么要使用Servlet?
- 线程同步之利器(1)——可递归锁与非递归锁
- 神女峰
- “清心”(3)下位机wifi与stm32对接(闲扯不同工程师的风格)
- 欢迎使用CSDN-markdown编辑器