回溯专题-递归

适用问题

模板

void backtrace(){
    if(终止条件){
        存放结果;
        return;
    }   
    for(选择:本层集合中元素(树中节点孩子的数量就是集合的大小)){
        处理节点;
        backtrace();
        回溯:
    }
}

幂集问题

对于给定的正整数n,求1~n构成的集合的幂集。(即由1-n集合中所有子集构成的集合,包括全集和空集。
例如a[3]={1, 2, 3} .幂集为:{ }, {1}, {2}, {3}, {1 2}, {1 3}, {2 3}, {1 2 3}

回溯法
本问题的解空间为子集树,每个元素只有两种扩展,要么选择,要么不选择。

不选择a[i],下一状态(i+1,x[i]=0)
不选择a[i],下一状态(i+1,x[i]=1)

#include <stdio.h>
#include <stdlib.h>

void print(int a[],int result[],int n){
    printf("{");
    for(int i=0;i<n;i++){
        if(result[i]) printf("%2d",a[i]);
    }
    printf(" }");
    printf("\n");
}

void backtrace(int a[],int result[],int k,int num){
    //求幂集
    if(k==num) 
    {
        print(a,result,num); 
        return;
    }
    result[k] = 1;
    //将第k个元素放入集合
    backtrace(a,result,k+1,num);
    //回溯-递归
    result[k] = 0;
    //不讲第k个元素放入集合
    backtrace(a,result,k+1,num);
    //回溯,递归

}

int main()
{
    int nums[4] = {1,2,3,4};
    int result[4] = {0};
    backtrace(nums,result,0,4);
    return 0;
}

背包问题

简单的0-1背包问题和幂集问题类似,为找到一个符合要求的子集合。

#include <stdio.h>
#include <stdlib.h>

//背包问题-有w1,w2...wn 的n个物品,背包总能装重量s,求得一组结果使得放入背包中的中的物品质量和刚好为s
void print(int stuff[],int n,int result[]){
    for(int i=0;i<n;i++){
        if(result[i] == 1){
            printf("(%d  ,  %d) , ",i+1,stuff[i]);
        }
    }
    printf("\n");
}
void backtrace(int stuff[],int n,int k,int result[],int weight_all,int S){
    //stuff[]存放着各个货物的质量
    //n表示货物个数
    //k表示当前处理第k个物品
    //result表示结果数组
    //weight_all表示当前重量
    //S表示背包总容量
    if(weight_all == S){
        print(stuff,n,result);
        return;
    }
    if(k>=n) return;
    result[k] = 1;
    //第k个货物放入
    backtrace(stuff,n,k+1,result,weight_all+stuff[k],S);
    result[k] = 0;
    //第k个货物不放入
    backtrace(stuff,n,k+1,result,weight_all,S);
}
int main()
{
    int S = 50;
    int n = 10;
    int stuff[10] = {29,26,18,16,13,10,8,5,3,1};
    int result[10] = {0};
    backtrace(stuff,n,0,result,0,S);
    return 0;
}

全排列问题

设计算法求n个元素a1,a2,a3,…an的全排列。

#include <stdio.h>
#include <stdlib.h>

void swap(int *a,int *b){
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

void print(int a[],int n){
    for(int i=0;i<n;i++){
        printf("%2d",a[i]);
    }
    printf("\n");
}
//排列问题
void backtrace(int a[],int n,int k){
    //a是全排列数组,n是数组个数,当前在处理第k个元素
    if(k == n){
        print(a,n);
        return;
    }
    if(k>n) return;
    for(int i=k;i<n;i++){
        //不断交换k与后续元素
        swap(&a[i],&a[k]);
        //交换i和k
        backtrace(a,n,k+1);
        swap(&a[i],&a[k]);
        //换回来
    }
}

int main()
{
    int set[6] = {1,2,3};
    backtrace(set,3,0);
    return 0;
}

而诸如TSP之类的问题,都可以用全排列的思想去解决问题。

组合问题

设计算法求出从(a1,a2,a3,…,an)取出k个元素的所有组合。

#include <stdio.h>
#include <stdlib.h>

//组合问题
void print(int set[],int n,int result[]){
    printf("{ ");
    for(int i=0;i<n;i++){
        if(result[i] == 1){
            printf("%2d,",set[i]);
        }
    }
    printf(" }\n");
}
void backtrace(int set[],int n,int result[],int k,int num,int sub_set_num){
    //目前一抽取了num个元素了
    //当前处理第k个元素
    //sub_set_num为抽取元素的数量
    if(num == sub_set_num){
        print(set,n,result);
        return;
    }
    if(k>=n) return;
    //第k个放进去
    result[k] = 1;
    backtrace(set,n,result,k+1,num+1,sub_set_num);
    //不放第k个
    result[k] = 0;
    backtrace(set,n,result,k+1,num,sub_set_num);
}
int main()
{
    int k = 3;
    int n = 6;
    int set[6] = {1,2,3,4,5,6};
    int result[6] = {0};
    backtrace(set,6,result,0,0,k);
    return 0;
}

参考:https://blog.csdn.net/weixin_43931465/article/details/109113417

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kilig*

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值