递归实现排列型枚举

题目描述

1~n 这 n 个整数排成一行后随机打乱顺序,输出所有可能的次序。

输入格式

一个整数n。

输出格式

按照从小到大的顺序输出所有方案,每行1个。

首先,同一行相邻两个数用一个空格隔开。

其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面。

数据范围

1(leq) n (leq) 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;
            }
        }
    }
}


原文地址:https://www.cnblogs.com/Acapplella/p/13558356.html