面对许多实际问题时,需要求解满足特定条件的全部解或最优解,如著名的N皇后问题和旅行售货员问题。
此类问题,一般没有特定的计算规则用于解题,通常我们采用试探性的方法,在包含问题所有可能解的解空间树中,将所有可能的结果搜索一遍,从而获得我们期望的那一个解,或者是那一些解,一般就是满足一定条件的最优解,或是全部解。那么这里用到的解空间树是什么呢?
解空间树与回溯法
解空间树:
依据待解问题的特性,用树结构表示问题的解结构,用叶子表示所有问题所有可能解的一棵树。
回溯法:
回溯法是采用深度遍历的策略搜索解空间树,并随时判定当前结点是否满足解题要求,满足要求的继续向下搜索,不满足要求则回溯到树的上一层继续搜索另一棵子树,这种解决问题的方法就称为回溯法。
解空间树的建立:
就是将问题求解的一系列判断决策过程及各种可能的结果用树型结构呈现。
事实上,我们解题的过程是一个不断判断决策的过程,我们把每一步判断决策的过程对应于解空间树的一个分支结点,而各种可能的不同结果,则对应得到结点的每一个孩子及各棵子树,而一系列判断决策的解题过程,就对应着解空间树的生长过程;而问题最终所有可能的解,都会呈现在这棵解空间树的叶子上。
求解N皇后问题的回溯算法
- 首先,我们先考虑4皇后问题。
在一个4x4的棋盘上,放置4个皇后,要求给出使各皇后彼此不受攻击的所有可能的棋盘布局。彼此不受攻击的条件是皇后不能在同一行、同一列、同一对角线上。
该问题的解题判断过程是这样的:

- 下面来看旅行售货员问题:

- N皇后问题的回溯算法:
N皇后问题:
在给定的N*N棋盘上放置N个皇后,要求给出的各皇后彼此不受攻击的所有可能的棋盘布局。
可用一维数组X表示N皇后问题的解,X[i] 表示第i行的皇后所在的列号,由此保证两个皇后不在同一行;X[i]<>X[s],则第i行与第s行的皇后不在同一列;| i-s | <> | X[i]-X[s] |,则皇后不在同一对角线。
判断皇后位置是否满足约束条件的函数:
void place(int s){
//判s行X[s]位置与1至s-1行各皇后是否满足条件
for(i=1;i<s;i++)
if(abs(i-s)==abs(X[i]-X[s]) || X[i]==X[s])
return false;
return true;
}
N皇后问题回溯算法:
void Tria(int i,int n){//棋盘为n*n,第i行起求皇后布局
if(i>n) 输出X数组 //获满足条件布局
else
for(j=1;j<=n;j++){ //依次生成孩子结点
X[i]=j; //第i行皇后入第j列
if(place(i)) //结点满足条件,递归进入下一层
Trial(i+1,n);
}
}
本函数初始调用为:Tria(1,n)
关于蓝桥杯中2n皇后问题具体解法和AC代码见https://blog.youkuaiyun.com/ITmincherry/article/details/105399624
解空间树与分支限界法
分支限界法也是算法设计领域非常重要的一类算法设计方法,它与回溯法求解问题的方法类似,都是围绕解空间树,通过遍历解空间树来求解问题,所不同的是,对于分支限界法来讲,它需要对节点进行优先级的设计,而采用的是“广度优先”结合“优先队列”的策略来遍历解空间树,它更适用于求解问题的最优解或满足条件的一个解。
分支界限法搜索解空间树的策略是:
第一、从根开始,首先生成根结点的所有可能的儿子,同时计算每个儿子的优先级,并将其放入优先队列中。
第二、从优先队列中选择一个优先级最高,也就是最有可能得到最优解的一个结点出队,并作为当前结点,生成其所有可能的儿子结点、计算优先级并且放入优先队列。
重复第二步,直至到达叶子结点,找到满足要求的一个解,或搜索到最优解。
由上述介绍可知,分支限界法是依据结点优先级,从优先队列中选取下一个节点,继续进行解空间树的生长与搜索。
因此,结点优先级的设计极为重要,而对于不同的问题,其结点优先级的设计是完全不同的,这需要针对问题的性质进行深入到研究分析,进而核心的设计出结点优先级,而只要结点优先级设计的合理,分支限界法可以使得搜索朝着解空间树上代表最优解的叶子结点快速推进,从而快速的找到最优解。
由此可见,分支限界法更强调算法的效率,一般情况下,同样是求最优解的问题,分支限界法的效率要优于回溯法。
后记:网课笔记,感觉稀里糊涂的QAQ
本文介绍了解空间树的概念及其在解决N皇后问题和旅行售货员问题中的应用。解空间树是表示问题所有可能解的树结构,回溯法通过深度遍历搜索解。N皇后问题的回溯算法通过判断皇后位置约束来求解。分支限界法则利用优先级队列策略寻找最优解,效率通常优于回溯法。
2499

被折叠的 条评论
为什么被折叠?



