DFS有两种保存结果的方法,1.保存在全局(马走日),2.保存在dfs里面返回(暂时我还不会)
DFS只能保证可以搜到,但是不能保证是最短的
这题debug了好久,根本原因是我的dx和dy写错了。。。
#include
#include
#include
using namespace std;
const int N = 110;
int T, n, xa, ya, xb, yb;
char g[N][N];
bool st[N][N];
bool dfs(int x, int y)
{
if (g[x][y] == '#') return false;
if (x == xb && y == yb) return true;
st[x][y] = true;//保证不会搜到重复的点,
//因为系统帮我们维护了一个栈存储下我们遍历的每个状态,方便我们回溯回上一层是继续遍历赏一层的状态可以遍历到的点
//保证每个点都会搜到,
int dx[4] = {-1, 0, 0, 1};
int dy[4] = {0, 1, -1, 0};
for (int i = 0; i < 4; i ++ )
{
int a = x + dx[i], b = y + dy[i];
if (a < 0 || a >= n || b < 0 || b >= n) continue;
if (st[a][b]) continue;//这一步保证了我们不会搜到重复的点
if (dfs(a, b)) return true; //这里其实相当于入栈操作
}
return false;
}
int main ()
{
scanf("%d", &T);
while (T -- )
{
memset(st, 0, sizeof st);//必须要写在这一步,因为是多组测试数据,需要置0
scanf("%d", &n);
for (int i = 0; i < n; i ++ ) scanf("%s", g[i]);
scanf("%d%d%d%d", &xa, &ya, &xb, &yb);
if (dfs(xa, ya)) puts("YES");
else puts("NO");
}
return 0;
}
#include
#include
using namespace std;
// ios::sync_with_stdio(false);
// cin.tie(0);
// cout.tie(0);
const int N = 22;
int n, m;
char g[N][N];
int st[N][N];
int dfs(int x, int y)
{
int cnt = 1;//我还纳闷,如果全局变量cnt怎么靠cnt += dfs(a, b)计数的
//原来是在每次合法的递归中(遍历的时候会判断当前要递归的坐标是否合法)
//cnt都是1,然后一层一层返回1,并标记当前坐标被遍历过了
//最终统计出所有黑瓷砖的数量,不重不漏
st[x][y] = true;
int dx[4] = {-1, 0 ,0 ,1};
int dy[4] = {0, -1, 1, 0};
for (int i = 0; i < 4; i ++ )
{
int a = x + dx[i], b = y + dy[i];
if (g[a][b] != '.') continue;
if (st[a][b]) continue;
cnt += dfs(a, b);
}
return cnt;
}
int main ()
{
while(cin >> m >> n, n || m)//很巧妙的标准输入,题目说当在一行中读入的是两个零时,表示输入结束,
{ //并且有多组测试数据,只有到00 的时候才是数据结束
for (int i = 0; i < n; i ++ ) cin >> g[i];
int x, y;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < m; j ++ )
if (g[i][j] == '@')
{
x = i, y = j;
}
memset(st, 0, sizeof st);//多组数据, 所以每次都要置0
cout << dfs(x, y) << endl;
}
return 0;
}
dfs的时候如何用全局变量收集结果
#include
#include
using namespace std;
const int N = 9 + 1;
int n, m, x, y;
int ans;//有多少种路径
bool st[N][N];
void dfs(int x, int y, int cnt)
{
//这里没有判断是否有失败的情况,因为我们用st数组保证了我们只要按照我们设定的st==true规则一定可以找到一个结果
if (cnt == n * m)
{
ans ++;
return ;
}
st[x][y] = true;
int dx[8] = {-1, -2, -2, -1, 1, 2, 2, 1}, dy[8] = {-2, -1, 1, 2, 2, 1, -1, -2};//遍历规则,只要保证能把所有情况都遍历到即可
//不重不漏即可
for (int i = 0; i < 8; i ++ )
{
int a = x + dx[i], b = y + dy[i];
if (a < 0 || a >= n || b < 0 || b >= m) continue;
if (st[a][b]) continue;
dfs(a, b, cnt + 1);
}
st[x][y] = false;//前面递归递归完成功收集结果后,要记得恢复现场
}
int main ()
{
int T;
cin >> T;
while (T -- )
{
cin >> n >> m >> x >> y;
ans = 0;//多组数据,置0
memset(st, 0, sizeof st);//多组数据,置0
dfs(x, y, 1);
cout << ans << endl;
}
return 0;
}
#include
#include
#include
using namespace std;
const int N = 25;
int n;
char start;
string word[N];
int g[N][N];
int used[N];
int ans;
void dfs(string dragon, int last)//不论能否找到结果,反正ans取max,总能找到一条路可以把所有单词串起来并且接龙最长
{
ans = max((int)dragon.size(), ans);//不知道这里为什么要强转一下
used[last] ++ ;
for (int i = 0; i < n; i ++ )
{
if (g[last][i] && used[i] < 2)
{
/*
dragon += word[i].substr(g[last][i]);//不能这么写,除非后面跟着一个回溯
dfs(dragon, i);
dragon -= word[i].substr(g[last][i]);//可以这么写,但是我不知道string如何-=
*/
dfs(dragon + word[i].substr(g[last][i]), i);//相当于编译器手动帮我们进行回溯操作了
}
}
used[last] --;//回溯
}
int main()
{
cin >> n;
for (int i = 0; i < n; i ++ ) cin >> word[i];
cin >> start;
//打表,预处理一下可以接龙接的数组
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
{
string a = word[i], b = word[j];
for (int k = 1; k < min(a.size(), b.size()); k ++ )//k从1开始,至少得有一个字符重合
{
if (a.substr(a.size() - k, k) == b.substr(0, k))
{
g[i][j] = k;//正好直接将k存进去,记录第i个单词和第j个单词可以重合的长度为多少
break;//找到一个就可以break
}
}
}
for (int i = 0; i < n; i ++ )//找到一个开头字符为start的单词
if (word[i][0] == start)
dfs(word[i], i);
cout << ans;
return 0;
}