关于深度优先搜索,首先需要确定这道题是不是可以搜出答案,一直往下搜索,如果可以出答案,那就说明深搜是可以的。
首先,如果我们需要输出搜素中我们的选择,这时候我们可能需要传入一个表示当前走到哪里的参数,第二个,如果我们需要计算出和最大或者是最小问题,我们可能传入一个参数,用来表示他们的和,第三个参数,也就是我们经常说的步数,我们可能要记录我们走了多少步,所以我们往往需要一个step的参数,来表示我们走了多少步,又或者,我们需要选完这个数后,我们要选比这个数大的数,我们此时也需要记录我们当前的数。
初步谈完了关于参数的传入,我们来谈谈关于终止条件,为什么要有终止条件呢,这是很重要的,不然我们的搜索不会停止,无法得到我们需要的结构,搜说条件往往是我们已经遇到死胡同了,接下来没有路可以走了,或者是说,我们已经收集好我们要的东西了,我们不需要再进行搜素了,这些都是需要我们进行终止的,而往往伴随着终止的是一个更新,我们需要更新我们最大值啊1,或是更新我们的最小值啊,又或者进行输出啊,当然是满足我们终止的条件下进行的啦,然后别忘了,我们在终止完后要return哦,不然你搜完第一次就卡在那里了,哪里能达到我们搜索的目的呢,你说是吧。
再来谈谈我们搜说的核心部分,首先我们要试探一下,试探这个点的下一个点有没有被搜索过,也就是说我们在前面要有一个东西,也就是一个判断的数组,来表示我们的下一个东西有没有被搜索过,如果有,可以continue,如果没有,那就标记下一个点为被搜索的状态,并进行递归调用我们的dfs,传入我们的下一个搜索点,注意参数往往要改变,也许是步数的加一,也许是和的加,也可以是下一个点的值,都要结合题目要求具体分析,然后也是比较重要的一点,我们需要进行清理现场,就是说我们要把我们前面标记的拿掉,让他可选择,这样我们就完成了整个dfs的搜索过程。
第一次写这个写的并不好,我们还是来看题吧。
第一题,n皇后问题
P1219 [USACO1.5] 八皇后 Checker Challenge
#include
using namespace std;变量空间
主函数方面,我们正常输入,然后开搜就行。
题目是要我们输出列数,那我们按行进行搜索,那么参数自然也变成了行,一方面我们确认了行肯定不会重复,接下来我们只需要关心列数和对角线即可,同时我们也确定了终止条件,见下。
由于题目要求输出前三个解,我们需要一个total变量来记录我们收集了多少个解答,如果total小于2证明我们的解答需要进行输出,至于终止条件呢,就是我们已经搜索到最后一行了。
这里我们要输出答案,所以需要一个数组,来存储我们的答案。每次输出完就total加一就好了,别忘了return .
接下来,进入搜索好戏,按照我们前面说的,我们需要判断能不能进行搜索,自然是判断其这一列和这一对角线和另一对角线能不能走,如果能走,请标记一下,然后肆无忌惮的走下去,接下来恢复现场标记为0,哦耶,一道搜索题就被解决了。
于是乎,八皇后也不过尔尔,不过是从行开始搜素,判断一下列,对角线有没有被访问过,没有就搜索,然后判断终止条件,就是我们答案到底有几次,三次就不输出了,然后每次total加一下就可以了。
int a[100], b[100], c[100], d[100];
int total;
int n;
void queen(int i)
{
if (i > n)
{
if (total <= 2)
{
for (int k = 1; k <= n; k++)
cout << a[k] << " ";
cout << "\n";
}
total++;
return;
}
else
{
for (int j = 1; j <= n; j++)
{
if ((!b[j]) && (!c[i + j]) && (!d[i - j + n]))
{
a[i] = j;
b[j] = 1;
c[i + j] = 1;
d[i - j + n] = 1;
queen(i + 1);
b[j] = 0;
c[i + j] = 0;
d[i - j + n] = 0;
}
}
}
}
int main()
{
cin >> n;
queen(1);
cout << total;
return 0;
}
好咧,我们来看第二道,
我们依然来理清一下思路,首先我们有一堆数字,我们要从中选择,每个数可以选可以不选,我们不断进行选择,到3个数字后就进行回溯,并且记录次数就可以。
其实到这里我们其实提前确定了终止条件,就是我们的步数达到了k,我们顺带判断一下素数函数,如果可以我们就可以直接让答案ans++就好了,对了,我自己都差点忘了,我们要return!!!!
由于我们要计算和,那我们也需要一个用来计算和的参数,也就是sum,到这里我们就确认了两个参数,不过我们以后要从当前选的这个数后面的数字进行选择,所以我们还需要一个starx进一步选择,到这里我们已经确认了所有参数,最后一个可能会难以理解一点,不过没关系哈,我们可以代码见,由于这道题并没有什么需要进行标记,我们这里其实已经愉快的结束了,在下次搜索的时候只需要将m++,再将starx++就可以了,然后加上return 进行恢复现场就好了。
#include
#include
#include
#include
头文件
using namespace std;
变量空间
int n, k;
输入的数字和要选的数字
int a[100000];
long long ans = 0;
bool isprime(int a) {
if (a == 1)
{
return 0;
}
for (int i = 2; i * i <= a; i++)
{
if (a % i == 0)
return false;
}
return true;
}
一个判断素数的函数
void dfs(int m,int sum,int starx)
{
if (m==k)
{
if (isprime(sum))
{
ans++;
}
return;
}
for (int i = starx; i < n; i++)
{
dfs(m + 1, sum + a[i], i + 1);
}
return;
}
int main()
{
cin >> n;
cin >> k;
for (int i = 0; i
cin >> a[i];
}
输入工作
dfs(0, 0, 0);
cout << ans;
return 0;
}
气氛都烘托到这里了,那就再来一道。
这道题是标准的dfs好吧。
首先进行起点和终点的输入,至于终止条件,我们很容易就可以想到,就是我们到终止条件了,那我们的ans++,最后输出就好。
关于输入方面的我就不再进行赘述。
我们有一个迷宫对吧,我们得确定迷宫有没有被走过,不妨一开始假设所有迷宫格子都没有被走过,我们全部初始化为1,当然为0其实也不错,看个人习惯哈。
然后我们输入障碍物,因为障碍物不能走,我们将所在格子弄成0.这样我们就完成了预处理工作,
然后我们要dfs,我们直接从起点开始搜索就好,这道题也不需要步数,也不是总和,那我们就传入两个坐标就好。
在起点搜索之前,我们要先将起点弄成不能走,也就是0.这样才代表我们的起点已经被我们走过了。
好嘞,真正开搜,我们要搜素起点的上下左右,那我们自然可以一个个试试,但有更好的做法,弄两个偏移量数组,一个是x轴方向的偏移量,y轴方向同理,那我们就定义两个一维数组,然后传入4个x和y坐标即可,然后我们需要一层For循环,用来搜素这四个点,如果可以走,那么请在走之前,赋值为0,代表已经走过了,然后大胆走下去,由于我们改变了标记量,那我们就让他返回现场,再赋值为0就好。
于是一道搜素题就这样结束了。
是不是不是很难?
#include
using namespace std;
int maze[100][100] ={0};
int n, m, t, sx, sy, fx, fy, ans = 0;
int dx[4] = { -1,1,0,0 };
int dy[4] = { 0,0,-1,1 };
void dfs(int x, int y)
{
if (x == fx && y == fy)
{
ans++;
return;
}
for (int i = 0; i < 4; i++)
{
if (maze[x + dx[i]][y + dy[i]] == 1)
{
maze[x + dx[i]][y + dy[i]] = 0;
dfs(x + dx[i], y + dy[i]);
maze[x + dx[i]][y + dy[i]] = 1;
}
}
}
int main()
{
int x, y;
cin >> n >> m >> t;
cin >> sx >> sy >> fx >> fy;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
maze[i][j] = 1;地图的初始化,全部都能走
}
}
for (int i = 0; i < t; i++)
{
cin >> x >> y;
maze[x][y] = 0;障碍物的初始化,不能走
}
maze[sx][sy] = 0;起点标记为不能走。
dfs(sx, sy);
cout << ans;
return 0;好习惯,继续保持
}
今天就到这里了,感谢诸君与各位道友,人生何处不相逢,期待下次再见!