搜索与回溯
搜索和回溯
一、 概念
搜索是计算机程序设计中一种最基本、最常用的算法。搜索算法是直接基于计算机高速运算的
特点而使用的计算机求解方法。
它是从问题的初始状态出发,根据其中的约束条件,按照一定的策略,有序推进,不断深入,
对于达到的所有目标状态(解空间),一一验证,找到符合条件的解(可行解),或者找出所
有可行解中的最优解。
(一)、深度搜索
1、基本思想
深度优先搜索是将当前状态按照一定的规则顺序,先拓展一步得到一个新状态,
再对这个新状态递归拓展下去。如果无法拓展,则退回一步到上一个状态,再按
照原先设定的规则顺序重新寻找一个状态拓展。如此搜索,直至找到目标状态,
或者遍历完所有状态。所以,深度优先搜索也是一种“盲目”搜索。
对于图9.10-1所示的一个“无向图”,从顶点V0开始进行深度优先搜索,
得到的一个序列为:V0,V1,V2,V6,V5,V3,V4
2、深度优先搜索的算法框架
深度优先搜索(Depth First Search,DFS),简称深搜,
其状态“退回一步”的顺序符合“后进先出”的特点,
所以采用“栈”存储状态。深搜适用于要求所有解方案的题目。
深搜可以采用直接递归的方法实现,其算法框架如下:
void dfs(int dep, 参数表 );{
自定义参数 ;
if( 当前是目标状态 ){
输出解或者作计数、评价处理 ;
}else
for(i = 1; i <= 状态的拓展可能数 ; i++)
if( 第 i 种状态拓展可行 ){
维护自定义参数 ;
dfs(dep+1, 参数表 );
}
}
3、典型例题
(1)、八皇后原始版本
题目描述
在国际象棋棋盘上(8*8)放置八个皇后,使得任意两个皇后之间不能在同一行,同一列,也不能位于同于对角线上。问共有多少种不同的方法,并且按字典序从小到大指出各种不同的放法。
输入格式
无
输出格式
1 5 8 6 3 7 2 4
1 6 8 3 7 4 2 5
…
总方法数
样例
样例输入
无
样例输出
1 5 8 6 3 7 2 4
1 6 8 3 7 4 2 5
…
92
解题思想
用深搜模拟当前棋盘上皇后的位置,判断当前位置可不可以放下皇后
若可以,储存下皇后的纵坐标,当8个皇后放完之后开始下一轮模拟,
直到找到最后一种解
代码实现
#include<cmath>
#include<cstdio>
int n,i,a[101],sum,w[101][10],j;
bool judge(int N)
{
for(int j=1;j<N;j++)
{
if(abs(a[j]-a[N])==abs(j-N)||a[j]==a[N])
{
return false;
}
}
return true;
}
void save()
{
sum++;
for(int j=1;j<=n;j++)
{
w[sum][j]=a[j];
}
}
void solve(int i)
{
if(i>n)
{
save();
return ;
}
for(int j=1;j<=n;j++)
{
a[i]=j;
if(judge(i))
{
solve(i+1);
}
}
}
int main()
{
n=8;
solve(1);
for(i=1;i<=sum;i++)
{
for(j=1;j<=8;j++)
{
printf("%d ",w[i][j]);
}
printf("\n");
}
printf("%d",sum);
}
(2)、八皇后
题目描述
会下国际象棋的人都很清楚:皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。如何将8个皇后放在棋盘上(有 8 * 8 个方格),使它们谁也不能被吃掉!这就是著名的八皇后问题。对于某个满足要求的 8 皇后的摆放方法,定义一个皇后串 a 与之对应,即 a=b1b2…b8,其中 bi 为相应摆法中第 i 行皇后所处的列数。已经知道 8 皇后问题一共有 92 组解(即92个不同的皇后串)。 给出一个数 b,要求输出第 b 个串。串的比较是这样的:皇后串 x 置于皇后串 y 之前,当且仅当将 x 视为整数时比 y 小。
输入格式
第 1 行是测试数据的组数 n,后面跟着 n 行输入。每组测试数据占 1 行,包括一个正整数 b(1 <= b <= 92)。
输出格式
输出有 n 行,每行输出对应一个输入。输出应是一个正整数,是对应于 b 的皇后串。
样例
输入样例
2
1
92
输出样例
15863724
84136275
解题思想
利用上一题将所有皇后模拟出来的数组
直接打印对应组号就可以A掉
代码实现
#include<cmath>
#include<cstdio>
int n,i,a[101],sum,w[101][10],j,num,t;
bool judge(int N)
{
for(int j=1;j<N;j++)
{
if(abs(a[j]-a[N])==abs(j-N)||a[j]==a[N])
{
return false;
}
}
return true;
}
void save()
{
sum++;
for(int j=1;j<=n;j++)
{
w[sum][j]=a[j];
}
}
void solve(int i)
{
if(i>n)
{
save();
return ;
}
for(int j=1;j<=n;j++)
{