搜索之全排列和组合数

搜索之全排列和组合数

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值