算法之回溯算法

本文深入探讨了回溯算法,通过红绿灯、全排列、8皇后问题和迷宫问题等实例,详细解释了解空间的概念以及如何构建解空间的树形结构。文章强调在实现回溯算法时应采用迭代方式,并给出了通用的代码模板,帮助读者掌握回溯算法的核心思想和常见应用场景。
摘要由CSDN通过智能技术生成

回溯算法的核心就是迭代,本质上并没有区别。相比较“回溯法”这个名字,我觉得“嗅探法”这个命名对于回溯算法更有描述性,即像一只小动物那样,走一步,嗅探一下,再向“正确”的方向移动,再进行嗅探,直到走到终点。回溯算法并不难掌握,甚至可以总结为一个固定的、适用于许多编程题的套路,至于这个套路是什么,我先不说,大家一步一步看了解会更深一些。

解空间
在展示回溯算法前,有一个概念需要大家了解——解空间。回溯法的解空间是的形式(不了解什么是树的朋友请自己学习)。对于一个使用回溯算法的题目,如果可以把解空间构造出来,那么这个题就差不多可以解答了。解空间在我们学习的过程中已经有过使用,比如说在学习概率的时候,有许多题都需要用树形结构表示出所有的可能性。比如说摇骰子,摇三次,出现两个4和一个6的概率是多少?根据这个问题我们可以画出一个深度为3(摇三次),每个节点的度为6(骰子六个面)的树,共有6^3种结果,从中选取自己需要的结果。我们从这个例子可以看到使用解空间解决问题有两种作用:列举出所有的情况、选取特殊的结果(剪枝)。这两种操作分别对应了回溯算法的外在和内核。接下来我们用几个例子来了解回溯算法。

红绿灯

有一个红绿灯,上面有三个灯,每个灯有三种颜色,请分别用123表示三种颜色,得到这个红绿灯变色的可能性。
看完这个问题,有些朋友可能已经十指连动,写完了这样的一段代码

void light()
{
   
    for(int i=1;i<=3;i++)
	{
   
	    for(int j=1;j<=3;j++)
		{
   
		    for(int k=1;k<=3;k++)
			{
   
			    printf("%d%d%d",i,j,k);
				printf("\n");
			}
		}
	}
}

这段代码没有问题,三层for循环表示树的深度为3,每个for循环都是从1到3,表示每个节点的度为3,构造出了正确的解空间。虽然这样写是正确的,我们在使用回溯算法时不推荐这样写:3个灯是三层for循环,那么10个灯呢?不能真的写十层for循环吧。所以我们对代码进行改写,使用迭代的方式,但不改变代码的意思。

void light(int n,int z[])
{
   
    if(n==3)    /*迭代三次后停止,打印此时的数组z*/
	{
   
	    for(int i=0;i<3;i++)
		{
   
		    printf("%d",z[i]);
		}
		printf("\n");
	}
	for(int i=1;i<=3;i++)    /*对z[n]赋值,123分别赋值,然后再次迭代,对下一个位置进行赋值*/
	{
   
	    z[n]=i;
		light(n+1,z);
	}
}

通过这个例子,我们了解到使用回溯算法时,应该采用迭代的方式编写代码。下面我们通过一个简单的例子来熟悉回溯算法。

全排列

给定一个数组,里面有不重复的n个正整数,求它们的全排列。
求数组的全排列,直白地说,就是对每个数进行讨论:取,还是不取?这样这个问题可以进一步简化为与上面红绿灯问题相近的问题:有n个灯,每个灯有两种颜色,有几种可能性?这并不难,我们直接看代码。

void track(int z[],int n,int j,int A
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值