算法之回溯法学习记录

本文详细介绍了回溯法的基本原理,包括深度优先搜索策略和剪枝函数的应用。通过图的m着色问题为例,展示了如何设计和实现回溯算法,以及其在解决组合优化问题中的应用。
摘要由CSDN通过智能技术生成

简单学习回溯法,理解回溯法的原理,解题步骤,解空间树等问题

概念

回溯法在问题的解空间树中,按深度优先策略,从根结点出发搜索解空间树。算法搜索至解空间树的任意一点时,先判断该结点是否包含问题的解。如果肯定不包含,则跳过对该结点为根的子树的搜索,逐层向其祖先结点回溯;否则,进入该子树,继续按深度优先策略搜索。
这种以深度优先方式系统搜索问题解的算法称为回溯法,适合解组合数比较大的问题。

回溯算法的基本步骤

1.定义问题的解空间;

解空间(解空间树):一个复杂问题的解决方案是由若干个小的决策步骤组成的决策序列。

解空间
解空间的求解过程:
求解过程

可行解:解空间中满足约束条件的解空间。
最优解:使得目标函数取得最大或者最小值的可行解。

2.确定易于搜索的空间结构;
3.以深度优先的方式搜索解空间,并且在搜索的过程中使用剪枝函数避免无效搜索;

回溯算法要点

1.深度优先搜索
2.剪枝函数:

  • 约束函数减去在扩展节点处减去不满足约束的子树
  • 界限函数减去得不到最优解的子树;

回溯法的算法框架

1.迭代回溯框架

void iterativeBacktrack(void) {
	int t = 1;//表示当前的决策层在解空间中
	while (t > 0) {//算法一直回溯,直到找到一个解或者没有解为止
		if (f(n, t) < g(n, t)) {//检查函数f和g的返回值。如果f(n, t)的值小于g(n, t)的值,则执行下面的代码块
			for (int i = f(n, t); i < g(n, t); ++i) {//从f(n, t)开始,到g(n, t)结束。在每次迭代中,它都会尝试不同的决策
				x[t] = h(i);//对于当前的决策值i,将x[t]设置为函数h(i)的返回值。这可能是在设置一个变量或值来构建当前的解
				if (conStraint(t) && boundStraint(t)) {//检查当前解是否满足约束条件(由conStraint(t)表示)和边界条件(由boundStraint(t)表示)
					if (solution(t)) outPut(x);//如果当前解是一个有效的解,则输出该解。这里假设有一个函数outPut(x)来输出或返回找到的解。
					else t++; //如果当前解不是有效的解,则增加t的值,尝试在更高层的决策空间中寻找解
				}
			}
		else  t--;//如果函数f(n, t)的值大于或等于函数g(n, t)的值,则减少t的值,尝试在更低层的决策空间中寻找解。
		}
	}

2.递归回溯框架

void backTrack(int t){
	if(t > n)     //算法已搜索到叶子结点,一般到叶子结点就结束
		Output(x);
	else{
		for(int i = f(n,t); i < g(n ,t); ++i){//确定循环的范围
			x[t] = h(i);
			if(conStraint(t)&&boundStraint(t)){//如果满足边界条件和约束条件就继续
				backTrack(t+1);//满足条件,处理下一个决策层
			}
		}
	}
}

案例1:图的m着色问题

1.问题描述:给定无向连通图G和m种不同的颜色。用这些颜色为图G的各顶点着色,每个顶点着一种颜色,是否有一种着色法使G中任意相邻的2个顶点着不同颜色。
2.简单示例分析:5个区域,四种颜色,着色方案?
问题描述
3.解空间树:顶点数n=5,颜色种数m=4,问题的解空间可以表示为一刻高度为n+1=6,完全m=4叉树。如下图:

解空间树
4.算法设计:

  • 深度优先遍历
  • 剪枝函数:约束函数、界限函数
if ((a[k][j]==1)&&(x[j]==x[k])),即判断顶点j是否与顶点k相邻且颜色相同,
如果存在,不符合要求,退出循环。否则,继续遍历。

5.代码实现:

void Backtrack(int t){
	if (t>n){// 算法搜索到叶子结点
		sum++;
		for (int i=1; i<=n; i++)
			cout << x[i] << " ";
		cout << endl;
	}
	else{
	//在每一层的遍历过程中,每一个结点都有m种颜色的选择
		for (int i=1;i<=m;i++) {
			x[t]=i;//存储解向量
			if (Ok(t)) //如果没有被减枝就进行下一步操作
				Backtrack(t+1);
			x[t]=0;
		}
	}
}

bool Ok(int k) { // 检查颜色可用性
	for (int j=1;j<=n;j++){
		if ((a[k][j]==1)&&(x[j]==x[k])) { //相邻且颜色相同
					return false;
		}
	}
	return true;
}
  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值