回溯算法
回溯法是一种类似于穷举的解决方式
思路:遍历所有可选择元素或者数据,如果当前选择不符合问题要求就会产生回溯,即抛弃当前的选择回到上一个状态并进行其他的选择。
回溯法的两个例子
装载问题:
有n个集装箱装入载重量为W的轮船,第i个集装箱的重量为w[i],要求轮船装的质量最多,在装载质量相同的情况下,要求在质量相同的情况下,装载的数量最少,使用回溯法解决该问题。
此问题可分解为可数个决策(对于某个集装箱的选与不选),通过遍历决策的布尔代数(0|1)产生了问题解空间的满二叉树,所以这个问题是通过遍历二叉树实现遍历问题的所有解,当决策脱离了问题的要求就“回溯”,直到得到满足问题要求的解的决策。回溯法是对决策树的遍历。
使用回溯法,遍历集装箱,使用min,x[],保存装载的最优序列,
1、保证最优=》在重量最重和当前集装箱树<min时,更新集装箱序列。
2、裁剪条件=》当前集装箱数>min时或者当前重量>轮船载重时,直接回溯,
3、T(o) = O(n^2)

#include<stdio.h>
#define MAX 20
int n,W;//轮船的容量
int maxw;//最优解的重量
int minm;//存放集装箱个数
int x[MAX];//最优解选择序列
//装载回溯遍历(质量序列,物品数,当前选择的物品,物品总重量,当前选择序列,当前选择的数目)
void loading(int w[],int tw,int m,int op[],int i){
int j;
if(i>n){
if(tw<=W&&(tw>maxw||(tw==maxw&&m<minm))){
maxw = tw;
minm = m;
for(j=1;j<=n;j++)
x[j] = op[j];
}
}else{
op[i] = 1;
if(tw+w[i]<=W)
loading(w,tw+w[i],m+1,op,i+1);
//回溯
op[i] = 0;
if(m<=2)
loading(w,tw,m,op,i+1);
}
}
void display(int n){
printf("选择的集装箱:\n");
for(int i=1;i<=n;i++)
if(x[i]==1)
printf("选择第%d个集装箱\n",i);
printf("\n");
}
int main(){
//初始化轮船
n = 5;W = 10;
//集装箱质量
int w[] = {0,5,2,1,4,3};
//物品选择数组
int op[MAX];
loading(w,0,0,op,1);
display(n);
return 0;
}
这个问题体现了回溯的另一个特点,由于数组是引用变量,回溯时数组元素没有还原到未进行选择前的状态,所以加了一条语句进行还原。体现了回溯要保持和元数据相同。

#include<stdio.h>
void perm(char s[],int k,int n){
int i;
char tmp;
if(k==n-1){
for(i=0;i<n;i++)
printf("%c",s[i]);
printf("\n");
}else{
for(i=k;i<n;i++){
tmp = s[k];s[k] = s[i];s[i] = tmp;//交换s[k]与s[i]
perm(s,k+1,n);
tmp = s[k];s[k] = s[i];s[i] = tmp;//交换s[k]与s[i],恢复环境即回溯。
}
}
}
int main(){
int n=3;
char s[] = "123";
perm(s,0,n);
}


浙公网安备 33010602011771号