什么是回溯算法
回溯算法的概念:回溯算法是一种类似枚举但优于枚举的算法,它可以通过“剪枝”的方式去掉那些不可能的递归情况,从而得到实现解题目标的所有可行方案。回溯算法一般通过递归来实现,每个次递归前都要判断当前这种方案是不是有继续递归的必要,如果可以,就继续往深入递归,最终实现目标,如果在递归中发现不符合递归条件了,那么就“减掉”这个分支,程序回溯到之前的另一种可能性重新开始,继续往下递归,能递归到最后一步的方案一般称为可行解,我们可以统计可行解的数目,从而最终得到方案总数。
回溯算法的优点:回溯算法可以讨论所有可能的方案,不遗漏地进行判断,同时它也会放弃那些不可能的递归方案,节省程序的运行时间。
回溯算法的解题思路:首先分析题目,如果最终目标由一系列步骤组成,并且让你求最终目标的方案数目,那么可以尝试使用回溯算法。代码一般分为两部分,递归部分和下一步判断部分,递归部分以循环的形式遍历所有可能的情况,判断部分的布尔值反馈结果决定是否下一步递归或者“剪枝”,即写判断条件。最终在递归达到一定深度的时候判断方案可行,进行计数累加或保存方案。
回溯算法的例题1:N皇后问题
题目:大家常见的是八皇后问题,是N皇后问题的一种特殊情况。N皇后问题是指,在一个N*N的棋盘上,放置N个皇后,他们彼此不能处在相同行、列、对角线,求有多少种摆放方案。
分析:我们可以对N个皇后逐一放置,首先我们可以确定一行摆放一个皇后,每个皇后有N个可以摆放的位置,那么我们先假设第一个皇后放在第一行第一个位置,再判断第二个皇后的摆放,如果放在第二行第一个位置在同一列不符合条件,放在第二个位置是对角线也不符合条件,第三个位置就可以,所以放下这个皇后,接下来看第三个皇后的摆放,以此类推,每次判断不可摆放时,即剪去了这个分支。如果某次递归行数大于N,即棋盘摆满,方案可行,计数加一。
算法实现:
int[] x ; //先申明一个数组,等待皇后数量输入
int sum =0; //满足条件的情况的累计
int num ; // 棋盘的宽高
/**
* 回溯算法1:皇后问题入口方法
*/
public void bt1()
{
num = 8;
x= new int[num+1];
BT1(1); //开始第一次递归
System.out.println(sum);
}
/**
* 回溯算法1:递归方法
* @param num
* @return
*/
public void BT1(int t) //摆第t行
{
if(t > num) //棋盘摆完,计数加一
sum++;
else
{
for(int i=1;i<=num;i++) //从第一个位置开始试探直到最后一个
{
x[t]=i; //放在第i个位置
if(place(t)==true) //可以放置就开始放下一个
{
BT1(t+1);//下一行
}
}
}
}
/**
* 回溯算法1:判断位置是否可放
*/
public boolean place(int t)
{
for(int i=1;i<t;i++)
{
if(x[i]==x[t]||Math.abs(i-t)==Math.abs(x[i]-x[t]))//判断对角线及行列
{
return false;
}
}
return true;
}
回溯算法2:图着色问题
问题:给定一个拼图,颜色刚开始都是空白的,我们有四种颜色,要求为图形上色且相邻色块颜色不能相同。
分析:类似N皇后问题