【精选】算法设计与分析(第五章回溯法)

目录

前言

第五章回溯法

1、回溯法概念

2、回溯法可以求解的问题有哪些

3、回溯法算法设计的三个点

4、回溯法解空间树的两种类型(重点简答)

5、什么是活结点,什么是扩展结点,什么是死结点

6、回溯法搜索解空间时通常采用的两种策略

7、回溯法求解步骤

8、回溯法与深度优先遍历的异同(简答)

9、 回溯法=DFS+剪枝

10、解空间树为子集树和排列树的时间复杂度

11、 求解0/1背包问题(重点)

12、学会画解空间树(省略)

13、判断子集和个数是否存在解

结语


前言

总结算法设计与分析课程期末必记知识点。

第五章回溯法

1、回溯法概念

回溯法实际上是一个类似穷举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时就“回溯”,尝试其他路径,所以回溯法有“通用的解题法”之称。

2、回溯法可以求解的问题有哪些

可行解最优解

3、回溯法算法设计的三个点

(1)结点是如何扩展的。

(2)在解空间树中按什么方式搜索,一种是采用深度优先遍历(DFS),回溯法就是这种方式;另一种是采用广度优先遍历(BFS),下一章介绍的分支限界法就是这种方式。

(3)解空间树通常是十分庞大的,如何高效地找到问题的解。

4、回溯法解空间树的两种类型(重点简答)

当所给的问题是从n个元素的集合S中找出满足某种性质的子集时,相应的解空间树称为子集树。当所给的问题是确定n个元素满足某种性质的排列时,相应的解空间树称为排列树

5、什么是活结点,什么是扩展结点,什么是死结点

活结点:指自身已生成但其孩子结点没有全部生成的结点

扩展结点:指正在产生孩子结点的结点

死结点:指其所有子结点均已产生的结点

6、回溯法搜索解空间时通常采用的两种策略

一是:约束函数

二是:限界函数

这两类统称为剪枝函数

7、回溯法求解步骤

(1)针对给定的问题确定问题的解空间树,问题的解空间树应至少包含问题的一个解或者最优解。

(2)确定结点的扩展搜索规则。

(3)以深度优先方式搜索解空间树,并在搜索过程中可以采用剪枝函数来避免无效搜索。其中,深度优先方式可以选择递归回溯或者迭代(非递归)回溯。

8、回溯法与深度优先遍历的异同(简答)

相同点

  • 回溯法在实现上也是遵循深度优先的。

不同的

  • 访问次序不同
  • 访问次数不同
  • 剪枝不同
9、 回溯法=DFS+剪枝

在通常情况下,回溯法的效率会高于蛮力法

10、解空间树为子集树和排列树的时间复杂度

子集树的时间复杂度为:O(2^n)

排列树的时间复杂度为:O(n!)

11、 求解0/1背包问题(重点)

第一种

void dfs(int i, int tw, int tv, int rw, int op[])//求解0/1背包问题
{
	if (i > n)				//找到一个叶子结点
	{
		if (tw == W && tv > maxv)	//找到一个满足条件的更优解,保存它
		{
			maxv = tv;
			for (int j = 1; j <= n; j++)	//复制最优解
				x[j] = op[j];
		}
	}
	else                    //尚未找完所有物品
	{
		if (tw + w[i] < W)		//左孩子结点剪枝
		{
			op[i] = 1;			//选取第i个物品
			dfs(i + 1, tw + w[i], tv + v[i], rw - w[i], op);
		}
		if (tw + rw - w[i] >= W)		//右孩子结点剪枝
		{
			op[i] = 0;					//不选取第i个物品,回溯
			dfs(i + 1, tw, tv, rw - w[i], op);
		}
	}
}

第二种

void dfs(int i, int tw, int tv, int op[])//求解0/1背包问题
{
	if (i > n)				//找到一个叶子结点
	{
		maxv = tv;			//存放更优解
		for (int j = 1; j <= n; j++)
			x[i] = op[j];
	}
	else                    //尚未找完所有物品
	{
		if (tw + A[i].w <= W)	//左孩子结点剪枝
		{
			op[i] = 1;			//选取序号为i的物品
			dfs(i + 1, tw + A[i].w, tv + A[i].v, op);
		}
		if (bound(i, tw, tv) > maxv)	//右孩子结点剪枝
		{
			op[i] = 0;			//不选取序号为i的物品,回溯
			dfs(i + 1, tw, tv, op);
		}
	}
}
12、学会画解空间树(省略)
13、判断子集和个数是否存在解

重点记dfs函数

考法一: 

#include<stdio.h>
#define MAXN 20		//最多整数个数
//问题表示
int n = 4, W = 31;
int w[] = { 0,11,13,24,7 };//存放所有整数,不用下标0的元素
int count = 0;		//累计解个数
void dispasolution(int n)//输出一个解
{
	for (int j = 1; j <= n; j++)
		if (w[j] == 1)
			printf("\t将第%d个集装箱装上第一艘轮船\n", j);
		else
			printf("\t将第%d个集装箱装上第二艘轮船\n", j);
}
void dfs(int i, int tw, int rw, int x[])//求解子集和
{	//tw为考虑第i个整数时选取的整数和,rw为剩下的整数和
	if (i > n)//找到一个叶子结点
	{
		if (tw == W)//找到一个满足条件的解,输出它
			dispasolution(tw);
	}
	else            //尚未找完所有整数
	{
		if (tw + w[i] <= W)//左孩子结点剪枝:选取满足条件的整数w[i]
		{
			x[i] = 1;//选取第i个整数
			dfs(i + 1, tw + w[i], rw - w[i], x);
		}
		if (tw + rw - w[i] >= W)//右孩子结点剪枝
		{
			x[i] = 0;			//不选取第i个整数,回溯
			dfs(i + 1, tw, rw - w[i], x);
		}
	}
}
int main() {
	int x[MAXN];
	int rw = 0;//存放一个解向量
	for (int j = 1; j <= n; j++)
		rw += w[j];//求所有整数和rw
	dfs(1, 0, rw, x);//i从1开始
	return 0;
}

考法二:

#include<stdio.h>
#define MAXN 20		//最多整数个数
//问题表示
int n = 4, W;
int w[] = { 0,11,13,24,7 };	//存放所有整数,不用下标0的元素
bool dfs(int i, int tw, int rw)	//存放所有整数,不用下标0的元素
{
	if (i > n)						//找到一个叶子结点
	{
		if (tw == W)					//找到一个满足条件的解,返回true
		{
			return true;
		}
	}
	else                            //尚未找完所有物品
	{
		if (tw + w[i] <= W)				//左孩子结点剪枝
			return dfs(i + 1, tw + w[i], rw - w[i]);//选取第i个整数
		if (tw + rw - w[i] >= W)				//有孩子结点剪枝
			return dfs(i + 1, tw, rw - w[i]);	//不选取第i个整数,回溯
	}
	return false;
}

 考法三:

int count;						//全局变量,累计解个数
void dfs(int i, int tw, int rw)	//求解子集和
{
	if (i > n)						//找到一个叶子结点
	{
		if (tw == W)					//找到一个满足条件的解,count++
		{
			count++;
		}
	}
	else                            //尚未找完所有物品
	{
		if (tw + w[i] <= W)				//左孩子结点剪枝
			dfs(i + 1, tw + w[i], rw - w[i]);//选取第i个整数
		if (tw + rw - w[i] >= W)				//有孩子结点剪枝
			dfs(i + 1, tw, rw - w[i]);	//不选取第i个整数,回溯
	}
}

结语

第五章回溯法结束,下一章——第六章分支限界法

🌌点击下方个人名片,交流会更方便哦~(欢迎到博主主页加入我们的 CodeCrafters联盟一起交流学习)↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓  

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

命运之光

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

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

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

打赏作者

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

抵扣说明:

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

余额充值