达到国际象棋目标的最少步数 - 使用 BFS 进行骑士遍历
Minimum number steps to reach goal in chess - knight traversal with BFS
下面给出的代码有效地适用于大小小于 13 的国际象棋,但之后它会花费太多时间并且永远运行。
我想减少到达结束节点的时间。
此代码还找到从 starti、startj 到 endi、endj 的最小路径,其中 starti 和 startj 取值从 1 到 n-1。
这是我要解决的问题:
https://www.hackerrank.com/challenges/knightl-on-chessboard/problem
程序:
import java.util.LinkedList;<br>
import java.util.Scanner;
class Node {
int x,y,dist;
Node(int x, int y, int dist) {
this.x = x;
this.y = y;
this.dist = dist;
}
public String toString() {
return "x: "+ x +" y: "+y +" dist: "+dist;
}
}
class Solution {
public static boolean checkBound(int x, int y, int n) {
if(x >0 && y>0 && x<=n && y<=n)
return true;
return false;
}
public static void printAnswer(int answer[][], int n) {
for(int i=0; i<n-1; i++) {
for(int j=0; j<n-1; j++) {
System.out.print(answer[i][j]+" ");
}
System.out.println();
}
}
public static int findMinimumStep(int n, int[] start, int[] end, int a, int b) {
LinkedList<Node> queue = new LinkedList();
boolean visited[][] = new boolean[n+1][n+1];
queue.add(new Node(start[0],start[1],0));
int x,y;
int[] dx = new int[] {a, -a, a, -a, b, -b, b, -b};
int[] dy = new int[] {b, b, -b, -b, a, a, -a, -a};
while(!queue.isEmpty()) {
Node z = queue.removeFirst();
visited[z.x][z.y] = true;
if(z.x == end[0] && z.y == end[1])
return z.dist;
for(int i=0; i<8; i++)
{
x = z.x + dx[i];
y = z.y + dy[i];
if(checkBound(x,y,n) && !visited[x][y])
queue.add(new Node(x,y,z.dist+1));
}
}
return -1;
}
public static void main(String args[]) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int start[] = new int[] {1,1};
int goal[] = new int[] {n,n};
int answer[][] = new int[n-1][n-1];
for(int i=1; i<n; i++) {
for(int j=i; j<n; j++) {
int result = findMinimumStep(n, start, goal, i, j);
answer[i-1][j-1] = result;
answer[j-1][i-1] = result;
}
}
printAnswer(answer,n);
}
}
即使你优化了代码,也不会降低算法的复杂度。
我认为你需要考虑如何减少搜索space。或者按巧妙的顺序搜索。
我会去 A*-search
你设置 visited
太晚了,相同的单元格被多次添加到队列中,然后你从队列中弹出它们而不检查它们的访问状态,这让事情变得更糟。这导致队列的快速增长。
您需要在将 Node
添加到队列后立即设置 visited
:
if(checkBound(x,y,n) && !visited[x][y]) {
queue.add(new Node(x,y,z.dist+1));
visited[x][y] = true;
}
您的问题最有效的解决方案是Dijkstra's algorithm。将正方形视为节点,并向骑士可以访问的另一个 squares/nodes 绘制边。然后 运行 这个图的算法。它以对数时间执行,因此它可以很好地解决大问题。
MrSmith 建议的 A* 搜索是启发式的,因此我不建议将其用于此类问题。
Dijkstra是一个重要的算法,实现它会帮助你解决很多类似的问题,比如你也可以用同样的逻辑解决this problem问题。
下面给出的代码有效地适用于大小小于 13 的国际象棋,但之后它会花费太多时间并且永远运行。 我想减少到达结束节点的时间。 此代码还找到从 starti、startj 到 endi、endj 的最小路径,其中 starti 和 startj 取值从 1 到 n-1。
这是我要解决的问题:
https://www.hackerrank.com/challenges/knightl-on-chessboard/problem
程序:
import java.util.LinkedList;<br>
import java.util.Scanner;
class Node {
int x,y,dist;
Node(int x, int y, int dist) {
this.x = x;
this.y = y;
this.dist = dist;
}
public String toString() {
return "x: "+ x +" y: "+y +" dist: "+dist;
}
}
class Solution {
public static boolean checkBound(int x, int y, int n) {
if(x >0 && y>0 && x<=n && y<=n)
return true;
return false;
}
public static void printAnswer(int answer[][], int n) {
for(int i=0; i<n-1; i++) {
for(int j=0; j<n-1; j++) {
System.out.print(answer[i][j]+" ");
}
System.out.println();
}
}
public static int findMinimumStep(int n, int[] start, int[] end, int a, int b) {
LinkedList<Node> queue = new LinkedList();
boolean visited[][] = new boolean[n+1][n+1];
queue.add(new Node(start[0],start[1],0));
int x,y;
int[] dx = new int[] {a, -a, a, -a, b, -b, b, -b};
int[] dy = new int[] {b, b, -b, -b, a, a, -a, -a};
while(!queue.isEmpty()) {
Node z = queue.removeFirst();
visited[z.x][z.y] = true;
if(z.x == end[0] && z.y == end[1])
return z.dist;
for(int i=0; i<8; i++)
{
x = z.x + dx[i];
y = z.y + dy[i];
if(checkBound(x,y,n) && !visited[x][y])
queue.add(new Node(x,y,z.dist+1));
}
}
return -1;
}
public static void main(String args[]) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int start[] = new int[] {1,1};
int goal[] = new int[] {n,n};
int answer[][] = new int[n-1][n-1];
for(int i=1; i<n; i++) {
for(int j=i; j<n; j++) {
int result = findMinimumStep(n, start, goal, i, j);
answer[i-1][j-1] = result;
answer[j-1][i-1] = result;
}
}
printAnswer(answer,n);
}
}
即使你优化了代码,也不会降低算法的复杂度。
我认为你需要考虑如何减少搜索space。或者按巧妙的顺序搜索。
我会去 A*-search
你设置 visited
太晚了,相同的单元格被多次添加到队列中,然后你从队列中弹出它们而不检查它们的访问状态,这让事情变得更糟。这导致队列的快速增长。
您需要在将 Node
添加到队列后立即设置 visited
:
if(checkBound(x,y,n) && !visited[x][y]) {
queue.add(new Node(x,y,z.dist+1));
visited[x][y] = true;
}
您的问题最有效的解决方案是Dijkstra's algorithm。将正方形视为节点,并向骑士可以访问的另一个 squares/nodes 绘制边。然后 运行 这个图的算法。它以对数时间执行,因此它可以很好地解决大问题。
MrSmith 建议的 A* 搜索是启发式的,因此我不建议将其用于此类问题。
Dijkstra是一个重要的算法,实现它会帮助你解决很多类似的问题,比如你也可以用同样的逻辑解决this problem问题。