我的编程空间,编程开发者的网络收藏夹
学习永远不晚

C++算法学习之回溯法的应用

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

C++算法学习之回溯法的应用

回溯1

实验题目:n皇后

题目描述:

N皇后的排列,每行一个不冲突;N<=13。

输入要求:

一个数字N (6 <= N <= 13) 表示棋盘是N x N大小的

输出要求:

前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。

解的输出顺序为从上到下从左到右,小的优先输出

实验代码及注释:

#include<bits/stdc++.h>
using namespace std;

int q[15] = { 0 }; //记录n个皇后的摆放位置
// 下标为行,数组元素为列
int sum = 0;
int n;

void queen(int i)
{
	int j;
	int col, flag; 

	if (i == n + 1)//所有的行全部走完,即成功找到一种解法
	{
		sum++;
		if (sum <= 3) // 输出前三行结果
		{
			for (j = 1;j <= n;j++)
			{
				if (j == n)
					cout << q[j] << endl;
				else
					cout << q[j] << " ";
			}
		}
		return;
	}
	else
	{
		for (col = 1;col <= n;col++)//遍历i行的每一列
		{
			flag = 1; // 假定棋子可放在i行col列
			for (j = 1;j < i;j++)//n遍历前i行是否符合
			{
				if (col == q[j] || i - col == j - q[j] || i + col == j + q[j])
				{
					flag = 0; //与前面棋子发生冲突
					break;
				}
			}
			if (flag == 1)//未与前面棋子发生冲突
			{
				q[i] = col;
				queen(i + 1);//遍历下一行
			}
		}
	}
}
int main(void)
{
	cin >> n;
	memset(q, -1, sizeof(q)); //初始化棋子,-1表示未放上棋盘
	queen(1); //从第一行开始遍历
	cout << sum << endl;
	return 0;
}

算法分析与知识点:

本题采用回溯算法思想来解决N皇后问题,这里用一个q[N]数组来记录棋子摆放情况:

1.算法开始, 清空棋盘,当前行设为第一行,当前列设为第一列

2.在当前行,当前列的位置上判断是否满足条件(即保证经过这一点的行,列与斜线上都没有两个皇后),若不满足,跳到第4步

3.在当前位置上满足条件的情形:

  • 在当前位置放一个皇后,若当前行是最后一行,记录一个解;
  • 若当前行不是最后一行,当前行设为下一行, 当前列设为当前行的第一个待测位置;
  • 若当前行是最后一行,当前列不是最后一列,当前列设为下一列;
  • 若当前行是最后一行,当前列是最后一列,回溯,即清空当前行及以下各行的棋盘,然后,当前行设为上一行,当前列设为当前行的下一个待测位置;
  • 以上返回到第2步

4.在当前位置上不满足条件的情形:

若当前列不是最后一列,当前列设为下一列,返回到第2步;

若当前列是最后一列了,回溯,即,若当前行已经是第一行了,算法退出,否则,清空当前行及以下各行的棋盘,然后,当前行设为上一行,当前列设为当前行的

下一个待测位置,返回到第2步;

实验题目:符号三角形

题目描述:

符号三角形的 第1行有n个由“+”和“-”组成的符号 ,以后每行符号比上行少1个,2个同号下面是“+”,2个异号下面是“-” 。计算有多少个不同的符号三角形,使其所含“+” 和“-” 的个数相同。

输入要求:

整数n(n<=20)。

输出要求:

符合要求的符号三角形的个数。

实验代码及注释:

#include<bits/stdc++.h> 
using namespace std;
int a[30][30] = { 0 };
int n, sum = 0, sum1 = 0;


void check() {
	int t = n, sum2 = 0;
	while (t--) {
		for (int i = 1;i <= t;i++) {
			a[t][i] = 1 - (a[t + 1][i] + a[t + 1][i + 1]) % 2;  // 递推第t层i列的符号
			if (a[t][i])//若为+
				sum2++;
		}
	}
	if (2 * (sum1 + sum2) == (n * (n + 1) / 2)) //记录+总数是否为符号总数的一半
		sum++;
}
void dfs(int x) {  // x表示考虑顶层第x个位置的符号
	for (int i = 0;i < 2;i++) {
		//0=>-;1=>+
		if (i)
			sum1++; // 记录顶层+的数量
		a[n][x] = i;
		if (x == n)//考虑完顶层的一种符号摆放,进行检查
			check();
		else
			dfs(x + 1);
		if (i)
			sum1--; // 若上摆放为+,则+数量回退1
	}
}
int main()
{
	cin >> n;
	if ((n * (n + 1) / 2) % 2 == 1) //判断符号总数奇偶性
		cout << 0 << endl;
	else {
		dfs(1);
		cout << sum << endl;
	}
	return 0;
}

算法分析与知识点:

本题主要运用回溯的思想,这题的特点是不能输入元素,而且只要确定的顶层的n的符号的排列情况,就可以得到整个符号三角形的排列情况,因此只需要对符号三角形的顶层进行遍历就好了。题目中有要求+和-的数量要一样,所以符号三角形的符号总数要是偶数,否则解决方案数为0。

令0和1分别代表-和+,其他层在顶层确定后即确定了,不需要枚举。采用dfs对第一层的符号排列情况进行遍历,遍历完n后就可得到答案。

回溯 堂练

实验题目:森林迷宫

题目描述:

一天Luna在森林里探险的时候不小心走入了一个迷宫,迷宫可以看成是由n * n的格点组成,每个格点只有2种状态:^ 和 # ;前者表示可以通行后者表示不能通行。当Luna处在某个格点时,她只能移动到东南西北(或者说上下左右)四个方向之一的相邻格点上,Luna想要从起点A走到终点B(中途不能走出迷宫)。如果起点或者终点有一个不能通行(为#),则当做无法通行。

输入要求:

第1行是测试数据的组数k,后面跟着k组输入。

每组测试数据的第1行是一个正整数n (1 <= n <= 100),表示迷宫的规模是n * n的。

接下来是一个n * n的矩阵,矩阵中的元素为 . 或者 #。

再接下来一行是4个整数ar,ac,br,bc。表示A处在第ar行,第ac列,B处在第br行, 第bc列。注意坐标ar,ac,br,bc全部是从0开始计数的类似[1,4][5,6]被认为是覆盖了[1,6]。

输出要求:

YES或NO

实验代码及注释:

#include<bits/stdc++.h> 
using namespace std;
char s[105][105]; // 记录地图
int n, ha, la, hb, lb, dir[4][2] = { {0,-1},{0,1},{-1,0},{1,0} }, flag;//flag标记搜索完毕后是否能到达终点
void dfs(int ha, int la)
{
	if (ha == hb && la == lb) // 判断是否达到终点
	{
		flag = 1;
	}
	if (flag) {
		cout << "YES" << endl;
		return;
	}
	for (int i = 0;i < 4;i++)
	{
		int dx = ha + dir[i][0];
		int dy = la + dir[i][1];
		if (dx >= 0 && dx < n && dy >= 0 && dy < n && s[dx][dy] == '^')
		{
			s[dx][dy] = '#';//只走一次,每个方都要走一遍,只要连通,肯定能到终点
			dfs(dx, dy);
		}
	}
}
int main()
{
	int k;
	cin >> k;
	while (k--)
	{
		cin >> n;
		for (int i = 0;i < n;i++) for (int j = 0;j < n;j++) cin >> s[i][j];
		cin >> ha >> la >> hb >> lb;
		if (s[ha][la] == '#' || s[hb][lb] == '#') cout << "NO" << endl;//提前判断始点和终点是否符合要求
		else
		{
			flag = 0;
			dfs(ha, la); //dfs搜索路径
			if (flag == 0) cout << "NO" << endl;
		}
		
	}
	return 0;
}

算法分析与知识点:

本采用深度优先的搜索方式来搜索全部路径,大致思路为:从当前点出发,往四个方位探寻找出所有与之相邻的且尚未被访问过的点,从中暂时先选取一个点作为当前点继续上述过程,直到到达目的地或者再也无法探寻到能前进的点,再返回。如果当前搜索的点到达了目标点,flag标记为true,返回即可。若所有能到达的点都搜索完了,flag仍为false,则无法到达。

实验题目:地图着色

题目描述:

给定图G=(V, E),需要为图G的各顶点着色,是否有一种着色法使G中相邻的两个顶点有不同的颜色?

输入要求:

第一行是顶点的个数n(2≤n≤10),颜色数m(1≤m≤n)。

接下来是顶点之间的连接关系:a b;表示a和b相邻。顶点从1开始计。

当a,b同时为0时表示输入结束。

输出要求:

输出着色方案总数和最少颜色数。如果无可行方案,颜色数为0。

实验代码及注释:

#include<bits/stdc++.h> 
using namespace std;
#define N 10
int n, sum = 0, m;
int x[N + 1]; //记录可行解
int g[N + 1][N + 1];//邻接矩阵
int ans = N;
int ok(int t)  // 判断当前层节点是否可行
{
    for (int j = 1; j <= n; j++)
        if (g[t][j] == 1 && x[t] == x[j])
            return 0;
    return 1;
}

int num_m() {  //计算可行解中的颜色种类数
    int ans = 0;
    int temp[101] = { 0 };
    for (int i = 1;i <= n;i++) {
        temp[x[i]] = 1;
    }
    for (int i = 1;i <= 100;i++)
        ans += temp[i];
    return ans;
}
void back_track(int t)
{
    int i;
    if (t > n)
    {
        sum++; //找到可行解,总数+1
        //for (i = 1; i <= n; i++)
        //    printf("%d ", x[i]);
        // printf("\n");
        int xx = num_m();
        if (xx < ans)
            ans = xx;
    }
    else
    {
        for (int i = 1; i <= m; i++)// 遍历节点的每种颜色取值
        {
            x[t] = i;
            if (ok(t))
                back_track(t + 1);
            x[t] = 0;
        }
    }
}

int main()
{
    cin >> n >> m; //n个顶点,m种颜色

    int a, b;
    cin >> a >> b;
    while (!(a == 0 && b == 0)) { //构造邻接矩阵
        g[a][b] = 1;
        g[b][a] = 1;
        cin >> a >> b;

    }
    back_track(1);
    if (sum)
        cout << sum << " " << ans << endl;
    else
        cout << 0 << " " << 0 << endl;
    return 0;
}

算法分析与知识点:

这个问题和八皇后还有求子集和等问题都具有类似之处,其核心在通过遍历找到所有的问题子集 ,但是在递归遍历的时候,都在加一个判断,将那些明显不满足条件的情况给直接排出,减少问题的规模,其实这类问题,在递归遍历的时候都是类似与对一颗树的便利每个节点相当走到此时的状态,然后再判断此时的状态是否能继续走下去,如果不能就将其回溯到上一个节点,避免浪费时间。

给定图g(v,e)和m种颜色,如果这个图不是m可着色,给出否定回答,是的话找出所有不同着色法。

分析:

用邻接矩阵表示图g,如果顶点i跟j之间有边,则g[i][j] = 1,否则g[i][j] = 0.用整数1,2,…,m表示m种颜色,顶点i的颜色用x[i]表示,所以x[1:n]是一种着色方案。

在算法traceback中,当i>n时,就是所有顶点都上了色,得到新的m着色方案,当前m着色方案总数sum增一,输出方案。

当i<n时,就是未着色完所有顶点,当前顶点i有x[i] = 1, 2…m种颜色可图,对于每种颜色由函数ok判断可行性,并用dfs对可行颜色搜索,或减去不可行方案。

以上就是C++算法学习之回溯法的应用的详细内容,更多关于C++回溯法的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

C++算法学习之回溯法的应用

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

C++回溯法怎么应用

本文小编为大家详细介绍“C++回溯法怎么应用”,内容详细,步骤清晰,细节处理妥当,希望这篇“C++回溯法怎么应用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。回溯1实验题目:n皇后题目描述:N皇后的排列,每行一个
2023-06-30

C++ 递归函数在回溯算法中的应用?

递归函数在回溯算法中通过深度优先搜索决策树来解决问题:函数调用自身,探索决策树的分支。针对问题,函数会不断深入探索树状结构,并在做出错误决策后进行回溯。实战案例:八皇后问题中,函数通过递归放置皇后,并通过回溯来撤销错误放置的皇后,最终找到符
C++ 递归函数在回溯算法中的应用?
2024-04-24

C++回溯算法之深度优先搜索详细介绍

回溯在迷宫搜索中使用很常见,就是这条路走不通,然后返回前一个路口,继续下一条路。回溯算法说白了就是穷举法,下面让我们一起来看看回溯算法中深度优先搜索吧
2023-01-13

C语言全排列回溯算法怎么用

这篇文章主要介绍“C语言全排列回溯算法怎么用”,在日常操作中,相信很多人在C语言全排列回溯算法怎么用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C语言全排列回溯算法怎么用”的疑惑有所帮助!接下来,请跟着小编
2023-06-26

C++回溯算法中组合的相关问题分析

回溯算法并不是什么高效的算法,因为本质上时去遍历所有元素,找出所有可能,然后选出需要的答案。那为什么还要回溯法,简单来说,不是所有的问题都能用什么巧妙的方法来解决的
2023-03-15

C++回溯算法深度优先搜索的示例分析

小编给大家分享一下C++回溯算法深度优先搜索的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!扑克牌全排列假如有编号为1~ 3的3张扑克牌和编号为1~3的3个盒子,现在需要将3张牌分别放到3个盒子中去,且每个盒子只能
2023-06-29

C++回溯算法中组合的相关问题怎么解决

这篇文章主要讲解了“C++回溯算法中组合的相关问题怎么解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++回溯算法中组合的相关问题怎么解决”吧!回溯算法模板void backtracki
2023-07-05

C++回溯算法中的全排列问题分析探讨

递归中遇到一个问题全排列的问题,我看见回溯特别神奇,特此记录一下。对比一下深度优先搜索与广度优先搜索,个人感觉这里的回溯像是一种递归树中的深度优先搜索的算法,他不断构造往下延伸的深度,使其达到完全编列
2023-03-15

C++回溯算法中的全排列问题怎么解决

本文小编为大家详细介绍“C++回溯算法中的全排列问题怎么解决”,内容详细,步骤清晰,细节处理妥当,希望这篇“C++回溯算法中的全排列问题怎么解决”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。一、全排列全排列的特点
2023-07-05

C++中set的用法学习

Set是C++ STL(标准模板库)的一个容器类,它用于存储不同的值,并且可以按照特定顺序进行访问和操作。本文就来通过一些示例和大家简单讲讲set的用法吧
2023-05-19

C++技术中的机器学习:使用C++实现机器学习算法的并行编程

c++++ 中的并行编程可以极大地提高机器学习算法的效率。c++ 提供了线程等并行工具,以及 openmp 和 mpi 等 api。openmp 可用于共享内存并行,而 mpi 则适用于分布式内存并行。通过使用 openmp,可以并行化线性
C++技术中的机器学习:使用C++实现机器学习算法的并行编程
2024-05-12

C++技术中的机器学习:使用C++实现常见机器学习算法的指南

在 c++++ 中,机器学习算法的实施方式包括:线性回归:用于预测连续变量,步骤包括加载数据、计算权重和偏差、更新参数和预测。逻辑回归:用于预测离散变量,流程与线性回归类似,但使用 sigmoid 函数进行预测。支持向量机:一种强大的分类和
C++技术中的机器学习:使用C++实现常见机器学习算法的指南
2024-05-11

C++技术中的机器学习:使用C++实现机器学习算法的调试技巧

c++++ 中机器学习算法的调试技巧:使用断点和调试器进行精确错误识别และตรวจสอบสถานะของตัวแปร使用日志记录和跟踪记录关键变量和事件以了解算法行为利用 valgrind 和 gdb 等分析工具检测内存错误和获取程序状态
C++技术中的机器学习:使用C++实现机器学习算法的调试技巧
2024-05-11

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录