dfs 全排列算法(含重复元素)

本文深入解析了全排列算法,包括数字全排列、字符全排列及含重复元素的全排列实现方法,通过递归深度优先搜索策略,实现了不同场景下元素的所有可能组合。

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

1、数的全排列

求数字 1 ~ n 的全排列,例如 1~3 的全排列,输出 1 2 3, 1 3 2 , 2 1 3, 2 3 1, 3 1 2, 3 2 1

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

#define runfile freopen("E:/Code/CB/Root/data.txt", "r", stdin)
#define stopfile fclose(stdin)

const int maxn = 100;
int n,vis[maxn],perm[maxn];//标记数组,全排列

void dfs(int step)//全排列,step 为当前选择元素的数量
{
    if(step == n+1)//已经选满 n 个数,得到全排列,深搜结束
    {
        for(int i = 1; i <= n; i++)
        {
            cout<<perm[i]<<" ";
        }
        cout<<endl;
    }
    else
    {
        //从1~n个选中一个未被选中的元素,然后继续深搜。深搜结束之后回溯
        for(int i = 1; i <= n; i++)
        {
            if(!vis[i])//未被标记
            {
                vis[i] =1;//标记
                perm[step] = i;//记录
                dfs(step+1);//深搜下一步
                vis[i] = 0;//回溯
            }
        }
    }
}

int main()
{
//    runfile;
    ios::sync_with_stdio(false);
    while(cin>>n)
    {
        memset(vis, 0, sizeof(vis));
        dfs(1);
    }

//    stopfile;
    return 0;
}

2、字符的全排列

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

#define runfile freopen("E:/Code/CB/Root/data.txt", "r", stdin)
#define stopfile fclose(stdin)

const int maxn = 100;
int n,vis[200];//标记数组,全排列
char s[maxn],perm[maxn];

void dfs(int step)//全排列,step 为当前选择元素的数量
{
    if(step == n+1)//已经选满 n 个数,得到全排列,深搜结束
    {
        for(int i = 1; i <= n; i++)
        {
            cout<<perm[i]<<" ";
        }
        cout<<endl;
    }
    else
    {
        //从1~n个选中一个未被选中的元素,然后继续深搜。深搜结束之后回溯
        for(int i = 0; i < n; i++)
        {
            int temp = (int)s[i];//注意此处与数字标记的不同
            if(!vis[temp])//未被标记
            {
                vis[temp] =1;//标记
                perm[step] = s[i];//记录
                dfs(step+1);//深搜下一步
                vis[temp] = 0;//回溯
            }
        }
    }
}

int main()
{
//    runfile;
    ios::sync_with_stdio(false);
    while(scanf("%d",&n) !=  EOF)
    {
        getchar();
        for(int i = 0; i < n; i++)
        {
            scanf("%c",&s[i]);
        }
        getchar();
        memset(vis, 0, sizeof(vis));
        dfs(1);
    }

//    stopfile;
    return 0;
}

3、含重复元素的全排列(首先要强制排序,然后再回溯的过程中记录上一个值的位置,保证相同的元素不会进行互换)

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

#define runfile freopen("E:/Code/CB/Root/data.txt", "r", stdin)
#define stopfile fclose(stdin)

const int maxn = 100;
int n,vis[maxn],pre;//标记数组,全排列
char s[maxn],perm[maxn];

void dfs(int step)//全排列,step 为当前选择元素的数量
{
    if(step == n+1)//已经选满 n 个数,得到全排列,深搜结束
    {
        for(int i = 1; i <= n; i++)
        {
            cout<<perm[i]<<"*";
        }
        cout<<endl;
    }
    else
    {
        //从1~n个选中一个未被选中的元素,然后继续深搜。深搜结束之后回溯
        int pre = -1;//记录前一个选中的根节点
        for(int i = 0; i < n; i++)
        {
            if(i == 0 || s[i] != s[pre])
            {
                if(!vis[i])//未被标记
                {
                    vis[i] =1;//标记
                    perm[step] = s[i];//记录--相当于两个数交换的过程
                    dfs(step+1);//深搜下一步
                    vis[i] = 0;//回溯
                    pre = i;//记录 pre
                }
            }
        }
    }
}

int main()
{
//    runfile;
    ios::sync_with_stdio(false);
    while(scanf("%d",&n) !=  EOF)
    {
        getchar();
        for(int i = 0; i < n; i++)
        {
            scanf("%c",&s[i]);
        }
        getchar();
        sort(s, s+n);//先强制排序
        memset(vis, 0, sizeof(vis));
        dfs(1);
    }

//    stopfile;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值