DFS有重复数字的全排列

此文写于2017-11-25

有重复数字的全排列

全排列就不说了,一个next_permutation就解决了。
但是有重复的数字还能用基本的全排列吗?
答案显然是不能的,我们需要一些语句来帮助我们避免重复。

方法一

让我们结合代码来分析

//有重复的全排列
#include<cstdio> 
#include<algorithm> 
using namespace std; 
const int MN=105; 
int a[MN],n,x,ans[MN],l; 
bool vis[MN]; 
void print() 
{ 
    for(int i=1;i<=n;i++) 
        printf("%d ",ans[i]); 
    printf("\n"); 
} 
void dfs(int k) 
{ 
    if(k>n) {print();return;} 
    int last=-1; 
    for(int i=1;i<=n;i++) 
        if(vis[i]==false&&a[i]!=last) 
            vis[i]=true,ans[k]=a[i],last=a[i],dfs(k+1),vis[i]=false; 
} 
int main() 
{ 
    scanf("%d",&n); 
    for(int i=1;i<=n;i++) 
        scanf("%d",&a[i]); 
    sort(a+1,a+n+1); 
    dfs(1); 
    return 0; 
} 

我们主要来说说这个dfs函数
如果k>n,那么就说明到了边界,直接输出;
关键是中间的判断重复与查找排列这一部分了
这段代码采用的是判断是否与上一个数字重复–可能不太好理解,我举个例吧:
例如输入的是:1 2 2
那么它的全排列就是:
①1 2 2
②2 1 2
③2 2 1
执行过程是这样的
首先进去就是1 2 2
然后返回变成1 2
发现不能是1 2 2
然后返回成1
发现不能是1 2
然后返回,更新成2
然后更新成2 1 2
返回变成2 1
返回变成2
更新成2 2 1
完毕

方法二

我们发现,我们可以直接利用数字出现的次数来做,方法如下,看代码就会(计数法)(约定一下数字大小不超过30)

#include<cstdio>
#include<algorithm>
using namespace std;
int b[105];
int ans[105],n,a[105],cnt;
void dfs(int k)
{
    if(k>n)
    {
        for(int i=1;i<n;i++) printf("%d ",ans[i]);
        printf("%d\n",ans[n]);
        return;
    }
    for(int i=1;i<=30;i++)
        if(b[i])
        {
            ans[k]=i;
            b[i]--;
            dfs(k+1);
            b[i]++;
        }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        b[a[i]]++;
    }
    sort(a+1,a+n+1);
    dfs(1);
    return 0;
}

戳我查看更多博客

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值