算法题每日一练---第21天:全排列

「这是我参与2022首次更文挑战的第22天,活动详情查看:2022首次更文挑战

一、问题描述

按照字典序输出自然数 1 到 n 所有不重复的排列,即 n 的全排列(1≤n≤9),要求所产生的任一数字序列中不允许出现重复的数字。

例如3的全排列为

    1    2    3
    1    3    2
    2    1    3
    2    3    1
    3    1    2
    3    2    1
复制代码

二、题目要求

输入格式

一个整数 n。

输出格式

由 1∼n 组成的所有不重复的数字序列,每行一个序列。

每个数字保留 5 个宽度。

三、问题分析

1.公式法

看到问题,很自然就会想到C++里面的全排列公式,一步解决。 头文件algorithm,a代表数组名称,n代表数组大小

do
{

}while(next_permutation(a,a+n));
复制代码

2.DFS

第二种方法,深度搜索(DFS),对于一些大题来说应用广泛,这一题虽然直接使用全排列公式更加合适,今天还是了解一下DFS这种用法。

1.png DFS简单来说就是一只老鼠走迷宫,遇到走不通的道路,往回退一个(俗称回溯)。

2.png 与之相对的广度搜索(BFS)更像是,多只老鼠走迷宫,从一个点分别向多个方向发散,直到找到出口。

以全排列为例,设置一个访问数组visited[10],判断当前数字是否被访问过,0代表没有,1代表有。从1开始深度搜索,未被访问过的数字存入数组,置为1,对下一个数字深度搜索,直到大于给定的n,输出数组里面的数字,进行回溯,以此类推

四、编码实现

1.公式法

#include<iostream>
#include<algorithm>//头文件
using namespace std;
int main()
{
	int i,n,a[9];//初始化
	cin>>n;//输入n
	for(i=0;i<n;i++)
		a[i]=i+1;//初始化数组
	do
	{
		for(i=0;i<n;i++)//循环
		{
			printf("%5d",a[i]);//输出数组元素
		}
		cout<<"\n";
		
	}while(next_permutation(a,a+n));//全排列公式
	return 0;
}
复制代码

2.DFS

#include<iostream>
using namespace std;
int n,a[10],visited[10]={0};//初始化定义数字数组和访问数组
void DFS(int k)
{
	int i,j;
	if(k>n)//大于n
	{
		for(j=1;j<=n;j++)//输出数组里面的元素
		{
			printf("%5d",a[j]);
		}
		cout<<"\n";
	}
	else
	{
		for(i=1;i<=n;i++)//循环判断
		{
			if(!visited[i])//是否访问过
			{
				visited[i]=1;//置为1
				a[k]=i;//赋值当前i给到k
				DFS(k+1);//下一步
				visited[i]=0;//回溯
			}
		}
	}
}
int main()
{
	
	cin>>n;//输入n
	DFS(1);//从1开始深搜
	return 0;
}

复制代码

五、输出结果

输入3 3.png

猜你喜欢

转载自juejin.im/post/7062154770718392351