回溯法之排列组合问题

回溯法又称试探法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点为“回溯点”。

回溯与递归在实现排列组合问题时,总是要用到栈,因此当组合数比较大的时候效率不是很高。先介绍两种解决排列组合的特殊算法再介绍利用回溯法实现组合问题。

特殊组合算法:
  本算法的思路是开一个数组,其下标表示1到m个数,数组元素的值为1表示其下标   
  代表的数被选中,为0则没选中。     
  首先初始化,将数组前n个元素置1,表示第一个组合为前n个数。     
  然后从左到右扫描数组元素值的“10”组合,找到第一个“10”组合后将其变为   
  “01”组合,同时将其左边的所有“1”全部移动到数组的最左端。     
  当第一个“1”移动到数组的m-n的位置,即n个“1”全部移动到最右端时,就得   
  到了最后一个组合。     
  例如求5中选3的组合:     
  1   1   1   0   0   //1,2,3     
  1   1   0   1   0   //1,2,4     
  1   0   1   1   0   //1,3,4     
  0   1   1   1   0   //2,3,4     
  1   1   0   0   1   //1,2,5     
  1   0   1   0   1   //1,3,5     
  0   1   1   0   1   //2,3,5     
  1   0   0   1   1   //1,4,5     
  0   1   0   1   1   //2,4,5     
  0   0   1   1   1   //3,4,5  

特殊全排列算法:

 从1到N,输出全排列,共N!条。   
  分析:用N进制的方法。设一个N个单元的数组,对第一个单元做加一操作,满N进   
  一。每加一次一就判断一下各位数组单元有无重复,有则再转回去做加一操作,没   
  有则说明得到了一个排列方案。

回溯法递归实现组合问题的思路:

1. 首先从n个数中选取编号最大的数,然后在剩下的n-1个数里面选取m-1个数,直到从n-(m-1)个数中选取1个数为止。
2. 从n个数中选取编号次小的一个数,继续执行1步,直到当前可选编号最大的数为m。

//Node a[] 候选集
//int n 候选集里面元素的个数
//int m 需要从候选集中选出的元素个数
//Node b[] 用来保存被选出来的元素
//int M 和m一样表示需要从候选集中选出元素的个数

template
void combine(Node a[],int n,int m,Node b[],int M)
{
for (int i=n;i>=m;i--)  
{
b[m-1]=a[i-1];
if(m>1)
combine(a,n-1,m-1,b,M);
else
{
for(int j=M-1;j>=0;j--)
print(b[j]);
}
}
}


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