适用问题
模板
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