分治法求全排列

全排列问题:

给定n个字符{r1,r2,…,rn},要求生成这n个字符的全排序

 

算法思想:

设R={r1,r2,…,rn}是要进行排列的n个元素,Ri=R-{ri}。
集合X中元素的全排列记为perm(X)。
(ri)perm(X)表示在全排列perm(X)的每一个排列前加上前缀得到的排列。

R的全排列可归纳定义如下:
(1)当n=1时,perm(R)=(r),其中r是集合R中唯一的元素;
(2)当n>1时,perm(R)由(r1)perm(R1),(r2)perm(R2),…,(rn)perm(Rn)构成。

 

算法分析

         1、假设有两个数 1,2,他们的全排列是 1,2和2,1,即以1开头的2的全排列和以2开头的1的全排列,而1个数的全排列是其本身,即定义(1)部分。

         2、假设有三个数1,2,3,他们的全排列是 1,2,3;1,3,2;2,1,3;2,3,1;3,1,2;3,2,1六组,即定义(2)部分。

         3、定义(2)部分可以理解为:将整个数列中每一个数分别与第一个数交换后加其他数的全排列,因此每次都是处理后n-1个数的全排列

         4、123的全排列:首先遍历所有元素,然后把遍历到的每一个元素和第一个元素交换:

(1)1和1交换还是1,那么就有了1,(2,3)

(2)同理,2,3和第一个交换后有了2,(1,3)和3,(1,2)共3组

(3)交换完了后要交换回来,因为后面交换都是在原来的数列1,2,3的基础上交换的,所以在排列前要交换一次,排列后还要交换一次(还原)

(4)检查每组除了第一个元素之外剩余的元素,如果元素的个数是2,那么就对剩下的元素进行全排列(递归)。

(5)1(2,3)按第1~4步得到1,2,3;1,3,2

5、为什么要交换两次?会漏掉很多组合

 

执行步骤

         求n个元素a1,a2 ….an的全排列:由排列组合的知识可知,n个元素的全排列有n!种=n*(n-1)!种=n*(n-1)*(n-2)!种=….

         分析 :  n=1      out: a1

            n=2            out:  a1,a2

                                                        a2,a1

                            n=3            out:  a1,a2,a3

                                                        a1,a3,a2

                                                        a2,a1,a3

                                                        a2,a3,a1

                                                        a3,a1,a2

                                                        a3,a2,a1

   上述步骤可以用循环执行“交换位置,后跟剩余的序列的全排列”;对剩余的序列再次使用该方法,直至没有剩余序列(只有一个元素)

 

#include
#include
using namespace std;
void perm(char ch[],int s,int t)
{
 int i;
 if(s==t)
 {
  for(i=0;i<=t;i++)
   cout<   cout<  }
 else
 {
  for(i=s;i<=t;i++)
  {
   swap(ch[i],ch[s]);
   perm(ch,s+1,t);
   swap(ch[i],ch[s]);
  }
 }
}
int main()
{
 int i,n,m;
 char ch[1000];
 cin>>n;
 while(n--)
 {
  cin>>m;
  for(i=0;i    cin>>ch[i];
  perm(ch,0,m-1);
  if(n) cout<  }

你可能感兴趣的:(计算机算法设计)