热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

这篇文章介绍了C++算法中回溯法的一些应用,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

回溯1

实验题目:n皇后

题目描述:

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

输入要求:

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

输出要求:

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

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

实验代码及注释:

#include
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 <> n;
	memset(q, -1, sizeof(q)); //初始化棋子,-1表示未放上棋盘
	queen(1); //从第一行开始遍历
	cout <

算法分析与知识点:

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

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

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

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

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

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

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

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

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

实验题目:符号三角形

题目描述:

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

输入要求:

整数n(n<=20)。

输出要求:

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

实验代码及注释:

#include 
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 <

算法分析与知识点:

本题主要运用回溯的思想,这题的特点是不能输入元素,而且只要确定的顶层的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 
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" <= 0 && dx = 0 && dy > k;
	while (k--)
	{
		cin >> n;
		for (int i = 0;i > s[i][j];
		cin >> ha >> la >> hb >> lb;
		if (s[ha][la] == '#' || s[hb][lb] == '#') cout <<"NO" <

算法分析与知识点:

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

算法分析与知识点:

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

给定图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

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


推荐阅读
  • 视觉Transformer综述
    本文综述了视觉Transformer在计算机视觉领域的应用,从原始Transformer出发,详细介绍了其在图像分类、目标检测和图像分割等任务中的最新进展。文章不仅涵盖了基础的Transformer架构,还深入探讨了各类增强版Transformer模型的设计思路和技术细节。 ... [详细]
  • 贡献转移在计算每个元素的作用的时候,我们可以通过反向枚举作用效果,添加到作用元素的身上,这种方法叫做贡献转移。更正式的说, ... [详细]
  • 本文回顾了作者在求职阿里和腾讯实习生过程中,从最初的迷茫到最后成功获得Offer的心路历程。文中不仅分享了个人的面试经历,还提供了宝贵的面试准备建议和技巧。 ... [详细]
  • 本文深入探讨了动态赋值的概念及其在编程实践中的应用,特别是通过Java代码示例来展示如何利用循环结构动态地为数组分配值。 ... [详细]
  • OpenCV中的霍夫圆检测技术解析
    本文详细介绍了如何使用OpenCV库中的HoughCircles函数实现霍夫圆检测,并提供了具体的代码示例及参数解释。 ... [详细]
  • 网络流24题——试题库问题
    题目描述:假设一个试题库中有n道试题。每道试题都标明了所属类别。同一道题可能有多个类别属性。现要从题库中抽取m道题组成试卷。并要求试卷包含指定类型的试题。试设计一个满足要求的组卷算 ... [详细]
  • hlg_oj_1116_选美大赛这题是最长子序列,然后再求出路径就可以了。开始写的比较乱,用数组什么的,后来用了指针就好办了。现在把代码贴 ... [详细]
  • 本文将探讨一个经典算法问题——最大连续子数组和。我们将从问题定义出发,逐步深入理解其背后的逻辑,并通过实例分析加深理解。 ... [详细]
  • H5技术实现经典游戏《贪吃蛇》
    本文将分享一个使用HTML5技术实现的经典小游戏——《贪吃蛇》。通过H5技术,我们将探讨如何构建这款游戏的两种主要玩法:积分闯关和无尽模式。 ... [详细]
  • 在1995年,Simon Plouffe 发现了一种特殊的求和方法来表示某些常数。两年后,Bailey 和 Borwein 在他们的论文中发表了这一发现,这种方法被命名为 Bailey-Borwein-Plouffe (BBP) 公式。该问题要求计算圆周率 π 的第 n 个十六进制数字。 ... [详细]
  • 洛谷 P4009 汽车加油行驶问题 解析
    探讨了经典算法题目——汽车加油行驶问题,通过网络流和费用流的视角,深入解析了该问题的解决方案。本文将详细阐述如何利用最短路径算法解决这一问题,并提供详细的代码实现。 ... [详细]
  • Hanks博士是一位著名的生物技术专家,他的儿子Hankson对数学有着浓厚的兴趣。最近,Hankson遇到了一个有趣的数学问题,涉及求解特定条件下的正整数x,而不使用传统的辗转相除法。 ... [详细]
  • 本文探讨了使用普通生成函数和指数生成函数解决组合与排列问题的方法,特别是在处理特定路径计数问题时的应用。文章通过详细分析和代码实现,展示了如何高效地计算在给定条件下不相邻相同元素的排列数量。 ... [详细]
  • 本文详细介绍了Linux系统中信号量的相关函数,包括sem_init、sem_wait、sem_post和sem_destroy,解释了它们的功能和使用方法,并提供了示例代码。 ... [详细]
  • 本文将深入探讨C语言中的位操作符——按位与(&)、按位或(|)和按位异或(^),通过具体示例解释这些操作符如何在位级别上对数据进行操作。 ... [详细]
author-avatar
lookzana
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有