递归实现排列型枚举
递归实现排列型枚举
https://ac.nowcoder.com/acm/contest/998/C
更好的阅读体验: https://www.cnblogs.com/Acapplella/p/13558356.html
题目描述
把 1~n
这 n 个整数排成一行后随机打乱顺序,输出所有可能的次序。
输入格式
一个整数n。
输出格式
按照从小到大的顺序输出所有方案,每行1个。
首先,同一行相邻两个数用一个空格隔开。
其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面。
数据范围
1 n 9
输入样例
3
输出样例
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
思路
我们尝试用递归的方式解决:先输出所有以1开头的排列(这一步是递归调用),然后输出以2开头的排列(又是递归调用),接着是以3开头的排列······最后才是以n开头的排列。
以1开头的排列的特点是:第一位是1,后面是2~9
的排列。根据字典序的定义,这些2~9
的排列也必须按照字典序排列。不过需要注意的是,在输出时,每个排列的最前面要加上1
。这样一来,所设计的递归函数需要以下参数:
- 已经确定的“前缀”序列,以便输出。
- 需要进行全排列的元素集合,以便依次选做第一个元素。
因此我们可以得到下面的递归函数:
void dfs(int u,int ans) { if(ans==n)//递归边界 { for(int i=0;i<n;i++) cout<<stu[i]<<" "; cout<<endl; return; } int i=1,j=1; for(i=1;i<=n;i++) //尝试在stu[u]中填写各种整数i { for(j=0;j<ans;j++) { if(stu[j]==i)//如果i已经在stu[0]~stu[u-1]出现过,则不能再选 { break; } } if(j==ans) { stu[ans]=i; dfs(i,ans+1);//递归调用 } } }
循环变量i是当前考察的stu[ans]。为了检查元素i是否已经用过,我们需要内层循环中加入一个判断,如果发现有某个stu[j] == i时,则break(跳出内层循环)。如果最终j == ans,则说明i没有在序列中出现过,把它添加到序列末尾后递归调用。
递归C++ 代码
#include<iostream> using namespace std; int n; int stu[10]; void dfs(int u,int ans) { if(ans==n)//递归边界 { for(int i=0;i<n;i++) cout<<stu[i]<<" "; cout<<endl; return; } int i=1,j=1; for(i=1;i<=n;i++) //尝试在stu[u]中填写各种整数i { for(j=0;j<ans;j++) { if(stu[j]==i)//如果i已经在stu[0]~stu[u-1]出现过,则不能再选 { break; } } if(j==ans) { stu[ans]=i; dfs(i,ans+1);//递归调用 } } } int main() { ios::sync_with_stdio(false); cin.tie(0); cin>>n; dfs(1,0); return 0; }
递归Java代码
import java.util.Scanner; import java.io.OutputStreamWriter; import java.io.PrintWriter; public class Main { static int[] stu=new int[10]; static int[] vis=new int[10]; static int n; static PrintWriter out = new PrintWriter(System.out); public static void main(String[] args) { // TODO 自动生成的方法存根 Scanner sc=new Scanner(System.in); n=sc.nextInt(); dfs(1,0); out.flush(); } public static void dfs(int u,int ans) { if(ans==n)//递归边界 { for(int i=0;i<n;i++) out.print(stu[i]+" "); out.println(); return; } int i=1,j=1; for(i=1;i<=n;i++) //尝试在stu[u]中填写各种整数i { if(vis[i]==0) { vis[i]=1; stu[ans]=i; dfs(i,ans+1);//递归调用 vis[i]=0; } } } }
算法竞赛进阶指南 文章被收录于专栏
代码编织梦想