回溯时机:
当一个节点的一条分支走完回到该节点后,
这个节点的其他分支会受到沿前一个分支搜索时改变的值的影响时,
需要回溯。
而这个值往往是全局变量,且不在终止条件的条件语句的花括号中。
不要用到回溯的例题:(9条消息) 洛谷P2036 [COCI2008-2009#2] PERKET_IOv0id的博客-优快云博客
下面一题即用到回溯。
洛谷P1605 迷宫:
#include<iostream>
#include<cstring>
using namespace std;
int n, m, t,sx,sy,fx,fy,cnt=0,f[10][10],tx,ty;
void dfs(int x, int y)
{
if (f[x][y] == 1)
return;
if (x == fx && y == fy)
{
cnt++;
return;
}
f[x][y] = 1;
if (x + 1 <= n)
{
dfs(x + 1, y);
}//down
if (x - 1 >= 1)
{
dfs(x - 1, y);//up
}
if (y + 1 <= m)
{
dfs(x, y + 1);//right
}
if (y - 1 >= 1)
{
dfs(x, y - 1);//left
}
f[x][y] = 0;
}
int main()
{
cin >> n >> m >> t;
cin >> sx >> sy >> fx >> fy;
memset(f, 0, sizeof(f));
for (int i = 0; i < t; i++)
{
cin >> tx >> ty;
f[tx][ty] = 1;
}
dfs(sx, sy);
cout << cnt;
}
该题需要回溯
因为每次重复调用函数都要修改f数组(全局变量)的值,从而影响初始节点的其他支路的搜索
值得注意的是:
题中在每一个节点走完所有方向后,回溯该节点;
也可以在每一个if中
先令f[][]=1;
再在dfs()后令f[][]=0;
可以把问题看成,一个初始节点连着一个新节点,这个新节点连着几个方向
前一种回溯是走到一个新节点,在搜索完该新节点的所有方向后,才回溯到初始节点,
后一种回溯走到一个新节点,仅搜索完一个方向后,立即回到初始节点,然后又重新到达该新节点,搜索一个新的方向,再回到初始节点......依次往复直到该新节点的所有方向被探索完毕,就回到初始节点,不再到达该新节点。
两者结果相同,后者多出现在dfs中的for循环中,如题中,可以用for循环来遍历四个方向,每一次循环就可以用到第二种回溯。
此外,在dfs函数中添加参数以记录下每个节点的状态,可以减少回溯操作甚至避免回溯。