子集树和排列树


 假设现在有一列数a[0],a[1], ...a[n-1]

 ①如果一个问题的解的长度不是固定的,并且解和元素顺序无关,即可以从中选择0个或多个,那么解空间的个数将是指数级别的,为2^n,可以用下面的子集树来表示所有的解

 子集树的算法框架为:

 

void backtrack(int t) {//表示访问到第t层,t从0开始 
if (t == n)
 output(x); 
else 
for (int i = 0; i <= n; i++) {//表示选或不选a[t] 
  x[t] = i; 
  if(constraint(t) && bound(t)) 
   backtrack(t + 1); 
 } 
}


②如果解空间是由n个元素的排列形成,也就是说n个元素的每一个排列都是解空间中的一个元素,那么,最后解空间的组织形式是排列树

 排列树算法的基本框架为:

 

void backtrack(int t) 
{ 
    if(t == n) 
        output(x); 
    else 
        for(inti = t; i < n; i++) 
        { 
            swap(x[t], x[i]);                    1
            if(constraint(t) && bound(t)) 
            { 
                backtrack(t + 1);                2
                swap(x[t], x[i]);                3 
            } 
        } 
} 


遇到子集树和排列数的回溯问题,几乎都可以用上面的模板来套。

注意: 序列A表示“前缀”序列,以便输出,S表示需要进行全排列的元素集合,以便依次选做第一个元素。

void print_emu(序列 A, 集合S) { 
  if(序列A满了) 输出序列A; 
 else{ 
  <strong>1.按照从小到大依次考虑S中的每一个元素v 
  2.print_emu(在A的末尾加上v后得到新的序列, S-{v})</strong> 
 } 
} 

以n=3 为例说明递归的执行过程:初始化x[]={1,2,3}

开始时:t=1,n=3;

  进入Backtrack(1) 此时t=1,i=1,执行①此时x[1]=1与x[1]=1交换;

  然后执行②进入t=1,i=1 的Backtrack(2)执行t=2,i=2的①x[2]=2与x[2]=2交换;

  然后执行②进入t=2,i=2的Backtrack(3)执行t=3,i=3的①x[3]=3与x[3]=3交换;

  然后执行②进入Backtrack(4)输出x序列(1,2,3)。

  返回到Backtrack(3)层执行t=3,i=3的③x[3]=3与x[3]=3(即还原成原序列),返回到t=2,i=2的Backtrack(2)层执行③x[2]=2与x[2]=2交换,至此t=2,i=2执行完成。

  下面开始执行t=2,i=3执行①此时x[2]=2与x[3]=3交换;

  然后执行②进入t=2,i=3的Backtrack(3)执行t=3,i=3 的①x[3]=3与x[3]=3交换;

  然后执行②进入Backtrack(4)输出x序列(1,3,2)。

  返回到Backtrack(3)层执行t=3,i=3的③x[3]=3与x[3]=3(即还原成原序列1,3,2),返回到t=2,i=2的Backtrack(2)层执行③x[2]=3与x[3]=2(即还原成原序列1,2,3)交换,至此t=2,i=3执行完成。

至此t=1,i=1执行完成,

    下面关于执行t=1,i=2和t=1,i=3的过程与t=1,i=1类似。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值