回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。 回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。 问题的解空间通常是在搜索问题的解的过程中动态产生的,这是回溯算法的一个重要特性。 N皇后问题是一个非常有名的问题,目前最快的解决思路用到回溯算法,大家都在算法优化上做文章,好象目前普通计算机可以在10秒内搞定N<20的N_queen问题了 关于N皇后的问题我想后面专门找个时间好好再研究一下,(最近有些忙,老大给我一个任务,去研究一下WinCE和Symbian平台的并发解决方案,与我们的平台做对比,如果能认识一个相关平台的专家就好了。) 言归正传,下面通过一个实例加深对回溯算法的认识。 例:设有一个 n × m 的棋盘 (2<=n<=50,2<=m<=50),在棋盘上任一点有一个中国象棋马, 马走的规则为: 1 、马走日字 2 、马只能向右走 输入n , m 后,同时输入马起始的位置和终点的位置,试找出从起点到终点的所有路径的数目(若不存在从起点到终点的路径 , 则输出 0 )。 例如: (n=10,m=10),(1,5)( 起点 ),(3,5)( 终点 ) , 输出: 2 (即由 (1,5) 到 (3,5) 共有 2 条路径 ) 两种方法: ________________________________________________________________________ 一是递归 略 ________________________________________________________________________ 二是回溯 回溯法都是类似思路,所以程序的流程也是类似的,大致流程参照如下,任何回溯法问题都可套用。
// 记录当前地点
ii current = ii(stratx, starty);
// 记录回溯的地点
ii backtarce(current);
// 记录路径,堆栈的作用
vii path;
起点压栈 // 这个灵活使用
while(true)
{
if (是终点)
{
// 取决于找一个路径即可还是找所有路径个数
return or not
}
// 判断是否有路径可走,要考虑到回溯回来的位置
//(这个判断条件是所有回溯法解决问题的关键)
if (是否有路)
{
排除掉回溯的路径后, 选一条路径
当前路径压栈
}
else
{
if (栈不为空)
{
退栈,回溯
}
else
{
全部找完,退出
}
}
}
________________________________________________________________________ 完整代码
// china xiangqi horse
#include <iostream>
#include <vector>
using namespace std;
int N,M;
typedef pair<int, int> ii;
typedef vector< pair<int, int> > vii;
int main()
{
// 地图边界
cin >> N >> M;
L.clear();
int stratx,starty;
int endx,endy;
cin >> stratx >> starty;
cin >> endx >> endy;
// 记录当前地点
ii current = ii(stratx, starty);
// 记录回溯的地点
ii backtarce(current);
// 记录路径
vii path;
//
int sum = 0;
// 起点压栈
path.push_back(current);
while(true)
{
// 是否终点,是的话打印路径
if (current == ii(endx, endy))
{
#if 1
for( vii::iterator it = path.begin() ; it != path.end(); it++)
{
if (it != path.begin()) cout << "->";
cout << "(" << (*it).first << "," << (*it).second<< ")";
}
cout << endl;
#endif
++sum;
// return main(); // 如果只要找一条,则打开
}
int less = backtarce.second - current.second;
// 是否有路径可走
if ((current.first < endx)
&& (current.second > 0)
&& (current.second <= M)
&& (less != -2))
{
// 排除掉回溯的路径后, 选一条路径
if (less == 2){
current.first += 2;
current.second += 1;
}else if (less == 1){
current.first += 2;
current.second -= 1;
}else if (less == -1){
current.first += 1;
current.second -= 2;
}else{
current.first += 1;
current.second += 2;
}
// 当前路径压栈
path.push_back(current);
backtarce = current;
}
else
{
// 栈是否为空
if (!path.empty())
{
// 退栈,回溯
backtarce = path.back();
path.pop_back();
current = path.back();
}
else
{
// 全部找完,退出
break;
}
}
}
cout << "sum:" << sum << endl;
#endif
return main();
}