gpt4 book ai didi

algorithm - BFS 和 DFS 算法有什么区别?

转载 作者:塔克拉玛干 更新时间:2023-11-03 05:33:19 34 4
gpt4 key购买 nike

用 BFS 解决算法问题时发生超时。但是,有一个问题可以用 DFS 解决。为什么会出现这种差异?

问题是计算从(1,1)到(N,N)通过水平、垂直或对角线移动到达的次数。

如果问题由 BFS 解决(最坏情况),则需要 1331.0ms,而由 DFS 解决则需要 62.0ms。 (我创建并测试了 16 * 16 个数组。)

附上问题 URL。 (但请理解它是韩语。)网址> https://www.acmicpc.net/problem/17070

我想听到的答案是...

  1. 我认为 BFS 算法会更快,但为什么 DFS 更快?
  2. BFS 慢是因为队列中有很多元素吗?我想知道确切的原因。

实现

类(class)位置{

int x;
int y;
int dir;

public Location(int x, int y, int dir) {
super();
this.x = x;
this.y = y;
this.dir = dir;
}

公共(public)课主要{

static int[][] map;
static int Answer;
static int N;

public static void main(String args[]) throws IOException {

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;

N = Integer.parseInt(br.readLine());

map = new int[N + 1][N + 1];
for (int i = 1; i <= N; i++) {

st = new StringTokenizer(br.readLine());

for (int j = 1; j <= N; j++)
map[i][j] = Integer.parseInt(st.nextToken());
}
DFS(1, 2, 0);
System.out.println(Answer);
Answer = 0;
BFS(1, 2, 0);
System.out.println(Answer);
br.close();
}

static void DFS(int x, int y, int pre) {

if (x == N && y == N) {

Answer++;
return;
}

if (pre == 0) {

if (y + 1 <= N && map[x][y + 1] == 0)
DFS(x, y + 1, 0);

if (y + 1 <= N && map[x][y + 1] == 0 && x + 1 <= N && map[x + 1][y] == 0 && map[x + 1][y + 1] == 0)
DFS(x + 1, y + 1, 1);
} else if (pre == 1) {

if (y + 1 <= N && map[x][y + 1] == 0)
DFS(x, y + 1, 0);

if (x + 1 <= N && map[x + 1][y] == 0)
DFS(x + 1, y, 2);

if (y + 1 <= N && map[x][y + 1] == 0 && x + 1 <= N && map[x + 1][y] == 0 && map[x + 1][y + 1] == 0)
DFS(x + 1, y + 1, 1);
} else {

if (x + 1 <= N && map[x + 1][y] == 0)
DFS(x + 1, y, 2);

if (y + 1 <= N && map[x][y + 1] == 0 && x + 1 <= N && map[x + 1][y] == 0 && map[x + 1][y + 1] == 0)
DFS(x + 1, y + 1, 1);
}
}

static void BFS(int startX, int startY, int dir) {

ArrayDeque<Location> arrayDeque = new ArrayDeque<>();
arrayDeque.add(new Location(startX, startY, dir));

Location location;
int x, y, pre;

while(!arrayDeque.isEmpty()) {

location = arrayDeque.remove();
x = location.x;
y = location.y;
pre = location.dir;

if(x == N-1 && y == N-1) {
Answer++; continue;
}

if (pre == 0) {

if (y + 1 <= N && map[x][y + 1] == 0)
arrayDeque.add(new Location(x, y + 1, 0));

if (y + 1 <= N && map[x][y + 1] == 0 && x + 1 <= N && map[x + 1][y] == 0 && map[x + 1][y + 1] == 0)
arrayDeque.add(new Location(x + 1, y + 1, 1));
} else if (pre == 1) {

if (y + 1 <= N && map[x][y + 1] == 0)
arrayDeque.add(new Location(x, y + 1, 0));

if (x + 1 <= N && map[x + 1][y] == 0)
arrayDeque.add(new Location(x + 1, y, 2));

if (y + 1 <= N && map[x][y + 1] == 0 && x + 1 <= N && map[x + 1][y] == 0 && map[x + 1][y + 1] == 0)
arrayDeque.add(new Location(x + 1, y + 1, 1));
} else {

if (x + 1 <= N && map[x + 1][y] == 0)
arrayDeque.add(new Location(x + 1, y, 2));

if (y + 1 <= N && map[x][y + 1] == 0 && x + 1 <= N && map[x + 1][y] == 0 && map[x + 1][y + 1] == 0)
arrayDeque.add(new Location(x + 1, y + 1, 1));
}
}
}

最佳答案

BFS 和 DFS 都有 O(|V| + |E|)时间复杂度,而您遇到的时间差很可能是 BFS 实现中的错误造成的,该错误打破了循环不变性

实现 BFS 时最常见的错误之一是多次将相同的元素添加到队列中。应该只添加一个顶点 v到队列一次,这样你就可以确保它被删除一次。除非你这样做,否则渐近运行时(即它的复杂性)将不再是线性的。可以看到相关CLRS基于他们引入的循环不变概念,这一章的证明。

也就是说,BFS是一种遍历算法。它找出哪些 顶点是可达的,而不是到达每个顶点的路由数 v .如果您尝试计算方式的数量 K<sub>v</sub>到达每个 v来自 (1, 1)通过 BFS,复杂度变得比线性更大。 如果问题要求您查找K<sub>v</sub> ,那么您的方法应该是使用记忆化和动态规划,而不是 BFS。

具体来说,根据您提供的代码,您的算法似乎没有跟踪先前是否探索过顶点(即网格中的单元格)。这导致顶点被多次探索,这超过了使用 BFS 和 DFS 等图遍历算法的意义。使用我上面提到的术语,您将违反 BFS 的循环不变量,它声明每个顶点仅从队列中弹出一次。这会导致代码的复杂性远高于线性。

您应该查看术语memoization 并找出一种方法来找到(N, N) 的解决方案| ,使用您为 (N-1, N-1) 计算仅一次的解决方案, (N-1, N)(N, N-1) .

关于algorithm - BFS 和 DFS 算法有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55528606/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com