递归实现排列型枚举(手动模拟回溯过程)

文章介绍了如何利用深度优先搜索和回溯策略,通过代码示例解决将1到n个整数随机打乱并输出所有可能顺序的问题,强调了回溯过程在生成所有排列中的关键作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目​​​​​​

把 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. 全局变量定义path数组用于存储排列的数字,vis数组用于记录每个数字是否已经被使用过

  2. 深度优先搜索

    • 如果u大于n,表示已经填满了整个排列,那么就输出这个排列,然后返回。

    • 否则,对于1n的每一个数字i,如果i还没有被使用过,那么就将i标记为已经被使用,然后将i放入排列的第u位,然后递归地调用DFS(u+1),表示继续填充下一位。最后,取消i的标记,表示回溯。

核心思想是深度优先搜索回溯。在每一步中,都尝试将每一个还没有被使用过的数字放入当前的位置,然后递归地填充下一位。如果已经填满了整个排列,那么就输出这个排列。否则,如果当前的数字不能放入当前的位置,那么就回溯,尝试下一个数字。这样,就可以保证生成的是所有可能的排列,而不是某一部分的排列。这是一个非常经典的深度优先搜索和回溯的应用。

代码如下:

#include<bits/stdc++.h>
using namespace std;

const int N=10; // 定义全局常量N,表示排列的长度

int path[N]; // 用于存储排列的数组
int vis[N]; // 记录每个数字是否已经被使用过
int n; // 输入的排列长度

// 深度优先搜索函数
void DFS(int u)
{
    if(u>n) // 如果已经填满了整个排列
    {
        for(int i=1;i<=n;i++)
            cout<<path[i]<<" "; // 输出排列
        cout<<endl;
        return ;
    }
    
    for(int i=1;i<=n;i++)
    {
        if(!vis[i]) // 如果数字i还没有被使用过
        {
            vis[i]=1; // 标记数字i已经被使用
            path[u]=i; // 将数字i放入排列的第u位
            DFS(u+1); // 继续填充下一位
            vis[i]=0; // 回溯,取消数字i的标记
        }
    }
}

int main()
{
    cin>>n; // 输入排列的长度
    DFS(1); // 从第一位开始填充排列
    return 0;
}

关键点来了,许多小伙伴不知道回溯的流程,我刚开始也卡了好久,下面我用代码手动模拟了一下回溯流程,相信你们一定会有所收获。

DFS(1)
{
    for(int i=1;i<=n;i++)
    {
        if(!vis[1])
        {
            vis[1]=1;
            path[1]=1;
            DFS(2)
            {
                for(int i=1;i<=n;i++)
                {
                    if(!vis[2])
                    {
                        vis[2]=1;
                        path[2]=2;
                        DFS(3)
                        {
                            for(int i=1;i<=n;i++)
                            {
                                if(!vis[3])
                                {
                                    vis[3]=1;
                                    path[3]=3;
                                    DFS(4)
                                    {
                                        cout<<1 2 3 ; //输出1 2 3 
                                        return ;
                                    }
                                    vis[3]=0;
                                    //此时DFS(3)结束,回溯到DFS(2)
                                }
                            }
                        }
                        vis[2]=0;
                        //i++,此时i=3

                        if(!vis[3]=0)
                        {
                            vis[3]=0;
                            path[2]=3;
                            DFS(3)
                            {
                                for(int i=1;i<=n;i++)
                                {
                                    if(!vis[2]=0)
                                    {
                                        vis[2]=1;
                                        path[2]=3;
                                        DFS(4)
                                        {
                                            cout<< 1 3 2; //输出 1 3 2
                                        }
                                       ...........
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

余晴尽欢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值