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