您的位置:首页 > 其它

算法——回溯法

2012-07-10 09:30 155 查看

回溯法

回溯法有“通用的解题法”之称。用它可以系统地搜索一个问题的所有解或任一解。回溯法是一种即带有系统性又带有跳跃性的搜索算法。它在问题的解空间树中,按深度优先策略,从根节点出发搜索解空间树。算法搜索至解空间树的任一结点时,先判断该节点是否包含问题的解。如果不包含,则跳过对以该节点为根的子树的搜索,逐层向其它祖先节点回溯。否则,进入该子树,继续按照深度优先策略搜索。回溯法求问题的所有解时,要回溯到根,且根节点的所有子树都已被搜索遍才结束。回溯法求问题的一个解时,只要搜索到问题的一个解就可结束。这种以深度优先方式系统搜索问题的算法称为回溯法,它是用于解组合数大的问题。

问题的解空间

用回溯法解问题时,应明确定义问题的解空间。问题的解空间至少包含问题的一个(最优)解。例如对于有n种可选择物品的0-1背包问题,其解空间由长度为n的0-1向量组成。该解空间包含对变量的所有可能的0-1赋值。例如n=3时,其解空间是
{(0,0,0),(0,0,1),(0,1,0),(0,1,1),(1,0,0),(1,0,1),(1,1,0),(1,1,1)}
定义了问题的解空间后,还应该将解空间很好地组织起来,使得能用回溯法方便地搜索整个解空间。通常将解空间组织成树或者图的形式。
例如,对于n=3时的0-1背包问题,可用一颗完全的二叉树表示其解空间,如下图。

n后问题

//八皇后问题

// Queen.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "stdio.h"

class Queen{    //类Queen记录解空间中的节点信息
friend int nQueen(int);
private:
bool Place(int k);    //剪枝函数
void Backtrack(int t);    //递归函数
int n;    //皇后个数
int *x;    //当前解
long sum;    //当前可行的方案数
};

int abs(int ab)//求绝对值
{
return ab>0?ab:-ab;
}

bool Queen::Place(int k)    //剪枝函数
{
for(int j=1;j<k;j++)
{
//剪枝条件:如果在同一行,同一列或者同斜线上
if((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k]))
return false;
}
return true;
}

void Queen::Backtrack(int t)    //递归回溯核心
{
if(t>n) sum++;    //如果遍历到叶子,说明求出了一个解
else
for(int i=1;i<=n;i++)
{
x[t]=i;
if(Place(t)) Backtrack(t+1); //函数Place为剪枝函数
}
}

int nQueen(int n)//初始化数据
{
Queen X;
X.n=n;
X.sum=0;
int *p=new int[n+1];
for(int i=0;i<=n;i++)
{
p[i]=0;
}
X.x=p;
X.Backtrack(1);
delete []p;
return X.sum;
}

int _tmain(int argc, _TCHAR* argv[])
{
printf("%d",nQueen(8));//传入参数8,即八皇后问题
return 0;
}


  测试结果:带入参数8,得到92种解,这个符合答案。



参考资料

维基百科:八皇后问题http://zh.wikipedia.org/wiki/%E5%85%AB%E7%9A%87%E5%90%8E%E9%97%AE%E9%A2%98计算机算法设计与分析/王晓东编著。-3版。-北京:电子工业出版社,2007.5
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: