全排列

OJ突然打不开了,下次把题目补上。

一开始看到题目,觉得是到简单题,用回溯法就解决了。然后,WA了无数次…

再次认真审题发现,输出结果是

1 2 3                          而不是      1 2 3

1 3 2                                            1 3 2

2 1 3                                            2 1 3

2 3 1                                            2 3 1

3 1 2                                            3 2 1

3 2 1                                            3 1 2

发现了问题就该改,但是从回溯中没想到改怎么改,在网上搜到了另一种方法——全排列的非递归算法,问题就解决了。

下面贴代码:

回溯法:

<pre name="code" class="cpp">void Perm(int *a,int k,int n)
{
     if(k==n-1)
     {
        for(int i=0;i<n;i++)
        {
           cout<<a[i];
           if(i!=n-1)
           {
              cout<<" ";
           }
        }
        cout<<endl;
     }
     else
     {
         for(int i=k;i<n;i++)
          {
              int t=a[k];a[k]=a[i];a[i]=t;          //改变元素位置
              Perm(a,k+1,n);
              t=a[k];a[k]=a[i];a[i]=t;              //将改变过的位置还原
           }
     }
}

递归算法通过选择元素,改变位置,达到组成所有排列的结果。

(递归的代码好写一点,也容易理解)

接下来,非递归算法

非递归算法是通过不断找下一个排列,直到找不到下一个排列就停止。(那什么时候找不到下一个排列?比如(3,1,2)的下一个是(3,2,1),而(3,2,1)就是最后一个。

不再有下一个,就这样不好理解,看代码。

(注:找下一个排列的方法,如(3,1,2),先从后向前找到序列中两个相邻并且递增的数,如(1,2),其中小得那个数(1)叫做替换数,它的下标叫做替换点。

然后从替换点向后找一个比替换数大的最小数(一定存在),把这个数和替换数交换,再将替换点后的所有数颠倒,得到的就是下一个排列(字典序)。)

例子:

(2,3,1,4) 先从最后向前找到递增且相邻的两个数1,4;再从1的后面找一个大于1的数,只有4,那么交换,得到(2,3,4,1),然后4以后的数颠倒,还是得到(2,3,4,1)

再找一个;从后向前找到递增且相邻的两个数3,4,;再从3后面找大于3的数,只有4,那么交换,得到(2,4,3,1),然后4以后的数颠倒,得到(2,4,1,3)

代码:

<pre name="code" class="cpp">bool Next_Permutation(int *a,int n)
{
     int i,t,k=n-1;
     while(k>0)
     {
          if(a[0]==a[k])   //排除重复元素造成的干扰
          {
             k--;continue;
          }
          t=k;
          k--;
          if(a[k]<a[t])              //找到递增并且相邻的两个数
          {
               int f=n-1;
               for(;f>t;f--)        //在替换点以后找一个大于替换数的最小的数
               {
                   if(a[f]<a[t]&&a[f]>a[k])
                    {break;}
               }
               int temp=a[f];a[f]=a[k];a[k]=temp;   //与替换数交换
               int p=t,q=n-1;
               while(p<=q)                            //电脑替换点以后的所有数
               {
                    temp=a[p];a[p]=a[q];a[q]=temp;
               }
          }
          return true;
     }
     return false;                              // 这就是最后找不到下一个排列,因为(4,3,2,1)中找不到相邻并且递增的两个数
}

点赞