zoukankan      html  css  js  c++  java
  • 回溯法求解全排列问题(可去除重复排列)

    1. 回溯法使用标记法求解

    
    include <cstdio>
    
    include <algorithm>
    
    using namespace std;
    int vis[100];   //标记数组,直接判断不需要循环判断,循环见全排列2.cpp
    int re[]= {2,1,2}; //给出数据
    int ans[100];//下标记录
    void dfs(int cur,int border)//可以去除重复排列,必须所给集合升序且正整数
    {
        int i,j,jl;
        if(cur==border)     //有满足条件的一组解
        {
            for(i=0; i<border; i++)
                printf("%d ",re[ans[i]]);
            putchar('
    ');
        }
        else
        {
            jl=0;                   //记录上一次这个节点的数值
            for(j=0; j<border; j++)
                if(!vis[j] && re[j]>jl)     //如果本次这个节点的值大于上一次就一定不重复
                {
                    ans[cur]=j;
                    jl=re[j];           //更新节点数值
                    vis[j]=1;           //标记走过的点
                    dfs(cur+1,border);  //满足条件进入下一层
                    vis[j]=0;           //递归返回的时候还原最初状态,有标记的一步一定要记住还原
                }
        }
    }
    int main(void)
    {
        sort(re,re+3);          //必须升序,排序算法才能保证不重复
        dfs(0,3);
        return 0;
    }
    

    2. 回溯法不使用标记数组,利用循环判断是否可行

    #include <cstdio>
    #include <algorithm> //这个全排列不使用标记数组
    using namespace std;
    int ans[100];
    int re[]= {1,2,1};
    void dfs(int cur,int border)
    {
        int i,j,k,ok,jl;
        if(cur>=border)
        {
            for(k=0; k<border; k++)
                printf("%d ",re[ans[k]]);
            putchar('
    ');
        }
        else
        {
            jl=0;
            for(j=0; j<border; j++)
            {
                ok=1;                       //先认为是有效值下面用循环进行检测是否有效
                ans[cur]=j;
                for(i=0; i<cur; i++)
                    if(j==ans[i])
                    {
                        ok=0;
                        break;
                    }
                if(ok && re[j]>jl)
                {
                    jl=re[j];
                    dfs(cur+1,border);
                }
            }
        }
    }
    int main(void)
    {
        sort(re,re+3);
        dfs(0,3);
        return 0;
    }
    

    3. STL库next_permulation()实现

    template<typename T>
    bool nextPermulation(T begin, T end)    //数据开始地址,结束地址
    {
        if(begin==end) return false;//空序列
        if(end==begin+1) return false;//一个元素
        T i=end-1;
        while(1)
        {
            T t=i;
            i--;
            if(*i < *t)
            {
                T j=end;
                while(!(*i < *--j));
                iter_swap(i,j);
                reverse(t,end);
                return true;
            }
            if(i==begin)
            {
                reverse(begin,end);         //已经为最大序列 例如:321
                return false;
            }
        }
    }

    算法描述:

    1、从尾部开始往前寻找两个相邻的元素第1个元素i,第2个元素j(从前往后数的),且 i < j

    2、再从尾往前找第一个大于i的元素k。将i、k**对调**

    3、[j,last)范围的元素置逆(颠倒排列)

  • 相关阅读:
    HDU 4644 BWT (KMP)
    常数的值类型问题
    HDU 1395 2^x mod n = 1 (欧拉函数)
    HDU 5384 Danganronpa(AC自动机)
    9.自己实现linux中的tree
    8.底层文件库
    7.标准文件库
    7.gcc的使用
    5.文件I/O
    4.vim操作
  • 原文地址:https://www.cnblogs.com/TianyuSu/p/9382814.html
Copyright © 2011-2022 走看看