• 搜索:枚举多重集排列


    我们假设A数组是方案数组,P数组是模板数组。

    对于每一种方案,从第一个位置开始放元素,一个一个放。

    我们原有的打印全排列的方法是不允许A数组中出现重复元素的,如下代码所示:

    void dfs(int dp)
    {
        if(dp>n)
        {
            for(int i=1;i<=n;i++)
                cout<<a[i]<<" ";
            ans++;
            cout<<endl;
            return;
        }
        for(int i=1;i<=n;i++)
        {
            if(!vis[i])
            {
                vis[i]=1;
                a[dp]=i;
                dfs(dp+1);
                a[dp]=0;
                vis[i]=0;
            }
        }
    } 

    解决方案如下

    我们在放每一个元素的时候,对于当前将要放的元素P[i],需要考虑已经在A数组中放置的元素里面(A[0]~A[cur-1]),P[i]出现的次数c1,以及模板数组P中P[i]出现的次数c2

    如果满足c1<c2就可以继续递归调用

    for(int k=0;k<cur;k++)
                if(P[i]==A[k])
                    c1++;
                for(int k=0;k<n;k++)
                if(P[i]==P[k])
                    c2++;

    以上的解决方案可以避免遗漏,但是会出现重复

    我们枚举的下标i应该不重复不遗漏地取模板数组中的每一个P[i],为了解决这一问题,我们事先将P数组从小到大排序,然后进行检查即可(相同的元素因排序会挨在一起)

     if(!i||P[i]!=P[i-1])

    之后便可以得到正确的结果。完整的代码如下,程序读入n和n个数,打印全排列。

    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=15;
    int P[maxn],A[maxn];
    void dfs(int cur,int n)
    {
        if(cur==n)
        {
            for(int i=0;i<n;i++)
                cout<<A[i]<<" ";
            cout<<endl;
            return;
        }
        for(int i=0;i<n;i++)
        {
            if(!i||P[i]!=P[i-1])
            {
                int c1=0,c2=0;
                for(int k=0;k<cur;k++)
                if(P[i]==A[k])
                    c1++;
                for(int k=0;k<n;k++)
                if(P[i]==P[k])
                    c2++;
                if(c1<c2)
                {
                    A[cur]=P[i];
                    dfs(cur+1,n);
                }
            }
        }
    }
    int main()
    {
        int n=0;
        cin>>n;
        for(int i=0;i<n;i++)
            scanf("%d",P+i);
        sort(P,P+n);
        dfs(0,n);
        return 0;
    }

    当然,我们完全可以把这个任务交给STL去完成,STL中的next_permutation函数会自动处理元素重复这一细节,用STL实现的代码如下:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int main()
    {
        int n, p[10];
        scanf("%d", &n);
        for(int i=0;i<n;i++)
        scanf("%d",&p[i]);
        sort(p,p+n);
        do
        {
            for(int i=0;i<n;i++)
                printf("%d ",p[i]);
            printf("
    ");
        }while(next_permutation(p, p+n));
        return 0;
    }

    用以上两种方法进行全排列的枚举可以避免本文刚开始案例之中dfs枚举全排列中不允许重复元素的问题,是通用的方法。

  • 相关阅读:
    IDEA最常用快捷键汇总+快速写出Main函数
    设计模式之代理模式
    Java多线程中join、yield、sleep方法详解
    git基础命令详解
    用友网络科技Java高级开发面试题(2019)
    Java内部类超详细总结(含代码示例)
    构造器中绝对绝对不能调用可被覆盖的方法
    写给小白看的Git的安装配置与使用
    Vue学习笔记5--前端工程化
    Vue学习笔记4--vue-router路由
  • 原文地址:https://www.cnblogs.com/aininot260/p/9269924.html
Copyright © 2020-2023  润新知