搜索之全排列和组合数
1.全排列问题
题目描述:
给定数 n n n 和 m m m ,表示从 $ 1$ 到 n n n 中随机抽取 $ m$ 个元素(区分顺序)
要求你打印输出所有的情况及总的个数
思路:
利用深搜的思想:
分析可知,由于我们一方面要知道选定的数是什么(范围是 1 到 n),另一方面要知道目前为止已经选了几个数(范围是1 到 m);
所以我们的递归函数可以含有两个参数,
即 dfs(int x,int k)
其中 x 表示目前选定的数是什么, k 表示目前为止选到了第几个数
知道了递归函数的参数以后,我们还需要知道跳出递归的条件:当选到 m 个数的时候,也就是这一组数已经选完了,就 return
再看具体搜索的实现:因为我们要求的是全排列,所以不管当前选定的是哪个数,都需要再从1开始寻找是否符合条件(即如果没有被搜到过就符合条件),用代码实现即:
(注意回溯操作)
for (int i = 1; i <= n; i++)
{
if (!f[i]) //判断是否搜过这个数
{
f[i] = 1; //现在已经搜到了,标记为1
a[k] = i; //存入数组
dfs(i,k+1); //继续搜
f[i] = 0; //回溯操作
a[k] = 0;
}
}
代码
#include<bits/stdc++.h>
#define N 100
using namespace std;
int n, m; int cnt;
int f[N]; int a[N];
void dfs(int x,int k)
{
if (k == m)
{
cnt++;
for (int i = 0; i < m; i++)
{
cout << a[i]<<" ";
}
cout << "\n";
return;
}
for (int i = 1; i <= n; i++)
{
if (!f[i])
{
f[i] = 1;
a[k] = i;
dfs(i,k+1);
f[i] = 0;
a[k] = 0;
}
}
}
int main()
{
cin >> n >> m;
dfs(0,0);
cout << cnt;
return 0;
}
2.组合数
思路:
与全排列不同的是,组合数选定的数是没有顺序的
换言之,后选定的数一定不会出现在已经选定的数的前面!!!
转化到代码上来看的话,与全排列不同的只有一点:那就是搜索不同的数的时候,每次搜索的起始位置不在是1,而是当前已经搜到的数的下一个!!!
即:
for (int i = x + 1; i <= n; i++) //注意这里是 i + 1 !!!!!!
{
if (!f[i])
{
f[i] = 1;
a[k] = i;
dfs(i,k+1);
f[i] = 0;
a[k] = 0;
}
}
代码:
#include<bits/stdc++.h>
#define N 100
using namespace std;
int n, m; int cnt;
int f[N]; int a[N];
void dfs(int x,int k)
{
if (k == m)
{
cnt++;
for (int i = 0; i < m; i++)
{
cout << a[i]<<" ";
}
cout << "\n";
return;
}
for (int i = x + 1; i <= n; i++)
{
if (!f[i])
{
f[i] = 1;
a[k] = i;
dfs(i,k+1);
f[i] = 0;
a[k] = 0;
}
}
}
int main()
{
cin >> n >> m;
dfs(0,0);
cout << cnt;
return 0;
}