详解排列组合

来源:互联网 发布:南京交通驾校 知乎 编辑:程序博客网 时间:2024/06/04 01:01

最近一直在研究搜索问题,发现了一个现象:很多搜索问题本质上其实就是排列组合的问题,只不过加上了某些剪枝和限制条件。在解决诸如此类的问题一般都会用到非空循环排列、全排列、一般组合或全组合。其中不重复排列和不重复组合就是一种剪枝的方法。为了理清自己的思路,同时也为了分享的目的就将自己的想法写下来。

首先说的是非空循环排列。

#include <iostream>using namespace std;const int MAX = 100;int result[MAX];void f(int *array, int arrayLength, int l, int n){if(l==n){for(int i=0; i < n; i++)cout << result[i] << ' ';cout << endl;return ;}for(int i=0; i < arrayLength; i++){result[l] = array[i];f(array, arrayLength, l+1, n);}}int main(){int arrayLength = 5;int array[5]={1,2,3,4,5};int count = 3;f(array, arrayLength, 0, count);return 0;} 


全排列,对一个数组进行全排列

 

#include <iostream>using namespace std;const int MAX = 100;int result[MAX];bool visit[MAX];void f(int *array, int arrayLength, int l, int n){if(l==n){for(int i=0; i < n; i++)cout << result[i] << ' ';cout << endl;return ;}for(int i=0; i < arrayLength; i++){// 如果此值没有被访问过 if(!visit[i]){visit[i] = true;result[l] = array[i];f(array, arrayLength, l+1, n);// 递归回溯用 visit[i] = false;}}}void Init(){for(int i=0; i < MAX; i++)visit[i] = false;}int main(){int array[5]={1,2,3,4,5};int count = 3;Init();f(array, 5, 0, count);return 0;} 

在很多时候数据可能出现相等的情况,而我们又不需要相同的数据,那么我们就可以把重复的数据数据排除,这就是不重复排列。在搜索中会当做剪枝用到。

比如:1,1,2

不重复排列之后就是:1,1,2

1,2,1

2,1,1

代码如下:

#include <iostream>using namespace std;const int MAX = 10;int number[MAX], used[MAX], result[MAX];int n;void f(int l){if(l==n){for(int i=0; i < n; i++)cout << result[i] << ' ';cout << endl;return ; }for(int i=0; i < n; i++){if(used[i]>0){used[i]--;result[l] = number[i];f(l+1);used[i]++;}}}void readData(){int count=0, value;cin >> n;for(int i=0; i < n; i++){cin >> value;int j;for(j=0; j < count;j ++){if(number[j]==value){used[j]++;break;}}if(j==count){used[count]=1;number[count++] = value;}}}int main(){readData();cout << "Result is :" << endl;f(0);return 0;}

不重复排列就是对全排列做了一次剪枝,在录入数据的时候用一个数组将真正的数保存起来,并另外用一个数组把每个数出现的次数也保存起来,那么在做递归的时候,在全排列中是判断某一个数是否有没有使用过,而这里其实也是一样,如果出现的次数大于一的话,那么就递减一表明其中一个数已经出现过了。

 

一般组合:n个数中取个数求组合 


#include <iostream>using namespace std;const int MAX = 10;int number[MAX], result[MAX];int n, m;void f(int l, int p){if(l==m){for(int i=0; i < m; i++)cout << result[i] << ' ';cout << endl;return ;}for(int i=p; i < n; i++){result[l] = number[i];f(l+1, i+1);}}void readData(){cin >> n >> m;for(int i=0; i < n; i++)cin >> number[i];}int main(){readData();f(0,0);return 0;} 

全组合:输出一个集合中所有的子集。2^n


#include <iostream>using namespace std;const int MAX = 10;int number[MAX], result[MAX];int n;void f(int l, int p){for(int i=0;i< l; i++)cout << result[i] <<' ';cout << endl;for(int i=p; i < n; i++){result[l] = number[i];f(l+1, i+1);}}void readData(){cin >> n;for(int i=0; i < n; i++)cin >> number[i];}int main(){readData();f(0,0);return 0;}


不重复的组合


#include <iostream>using namespace std;const int MAX =10;int number[MAX], used[MAX], result[MAX];int n;int count=0;void f(int l,int p){for(int i=0; i < l; i++)cout << result[i] << ' ';cout << endl;for(int i=p; i < count; i++){if(used[i]>0){used[i]--;result[l] = number[i];f(l+1, i);used[i]++;}}}void readData(){int  value;cin >> n;for(int i=0; i < n; i++){cin >> value;int j;for(j=0; j < count;j ++){if(number[j]==value){used[j]++;break;}}if(j==count){used[count]=1;number[count++] = value;}}}int main(){readData();f(0,0);return 0;} 




7 0
原创粉丝点击