英文:
Finding all unique possible moves of a knight
问题
我们有一个8x8的棋盘,单元格从1开始编号,我的目标是编写一个带有以下签名的函数:
public static String findPos(int i, int j, int n)
其中参数(i,j)是骑士在棋盘上的起始位置,而n是骑士将要进行的总移动次数(n≥0)。
例如:
调用findPos(1, 1, 0)
将返回(1, 1)
,因为在0次移动中,骑士只能停留在自己的位置。
调用findPos(1, 1, 1)
将返回(1, 1),(2, 3),(3, 2)
。
我已经写了一个不太优雅的解决方案,但它会计算骑士在某些情况下可能占据的重复位置,例如调用findPos(1, 1, 2)
:
public static String findPos(int i, int j, int n) {
if (n == 0) {
if (i >= 1 && j >= 1 && i <= 8 && j <= 8) {
return "(" + i + ", " + j + ")";
} else {
return "";
}
} else {
if (i >= 1 && j >= 1 && i <= 8 && j <= 8) {
return "(" + i + ", " + j + ")" +
findPos(i - 1, j - 2, n - 1) +
findPos(i - 2, j - 1, n - 1) +
findPos(i - 2, j + 1, n - 1) +
findPos(i - 1, j + 2, n - 1) +
findPos(i + 1, j + 2, n - 1) +
findPos(i + 2, j + 1, n - 1) +
findPos(i + 2, j - 1, n - 1) +
findPos(i + 1, j - 2, n - 1);
} else {
return findPos(i - 1, j - 2, n - 1) +
findPos(i - 2, j - 1, n - 1) +
findPos(i - 2, j + 1, n - 1) +
findPos(i - 1, j + 2, n - 1) +
findPos(i + 1, j + 2, n - 1) +
findPos(i + 2, j + 1, n - 1) +
findPos(i + 2, j - 1, n - 1) +
findPos(i + 1, j - 2, n - 1);
}
}
}
我的问题是:如何改进代码/递归,以便它只返回可能的唯一位置,因为目前它也会返回重复的位置?
英文:
we have a 8x8 board with cells starting from one, my goal is to write such a function with signature :
public static String findPos(int i, int j, int n)
which takes parameters (i,j) the starting position of the knight on the board , and n is the total moves it will make(n>=0)
For example:
findPos(1,1,0) will return (1,1) only since with 0 moves the knight can only stay at it's own position
findPos(1,1,1) will return (1,1),(2,3),(3,2)
I have wrote not really pretty solution , however it counts duplicate positions the knight can take in the case for example findPos(1,1,2):
public static String findPos(int i, int j, int n) {
if (n == 0) {
if (i >= 1 && j >= 1 && i <= 8 && j <= 8) {
return "(" + i + ", " + j + " )";;
} else {
return "";
}
} else {
if (i >= 1 && j >= 1 && i <= 8 && j <= 8) {
return "(" + i + ", " + j + " )" + findPos(i - 1, j - 2, n - 1)
+ findPos(i - 2, j - 1, n - 1)
+ findPos(i - 2, j + 1, n - 1)
+ findPos(i - 1, j + 2, n - 1)
+ findPos(i + 1, j + 2, n - 1)
+ findPos(i + 2, j + 1, n - 1)
+ findPos(i + 2, j - 1, n - 1)
+ findPos(i + 1, j - 2, n - 1);
} else {
return findPos(i - 1, j - 2, n - 1)
+ findPos(i - 2, j - 1, n - 1)
+ findPos(i - 2, j + 1, n - 1)
+ findPos(i - 1, j + 2, n - 1)
+ findPos(i + 1, j + 2, n - 1)
+ findPos(i + 2, j + 1, n - 1)
+ findPos(i + 2, j - 1, n - 1)
+ findPos(i + 1, j - 2, n - 1);
}
}
}
My question is :How can I improve the code/recursion so it returns only unique positions it can take, because currently it also writes dublicates?
答案1
得分: 0
在你的代码中,你使用了一个布尔数组来标记访问过的位置,以防止再次调用该位置。
以下是修改后的代码:
static boolean visited[][] = new boolean[9][9];
public static String findPos(int i, int j, int n) {
if(i<1 || i>8 || j<1 || j>8 || visited[i][j]) return "";
else {
visited[i][j] = true;
if (n == 0) {
if (i >= 1 && j >= 1 && i <= 8 && j <= 8) {
return "(" + i + ", " + j + ")";
} else {
return "";
}
} else {
if (i >= 1 && j >= 1 && i <= 8 && j <= 8) {
return "(" + i + ", " + j + ")" + findPos(i - 1, j - 2, n - 1)
+ findPos(i - 2, j - 1, n - 1)
+ findPos(i - 2, j + 1, n - 1)
+ findPos(i - 1, j + 2, n - 1)
+ findPos(i + 1, j + 2, n - 1)
+ findPos(i + 2, j + 1, n - 1)
+ findPos(i + 2, j - 1, n - 1)
+ findPos(i + 1, j - 2, n - 1);
} else {
return findPos(i - 1, j - 2, n - 1)
+ findPos(i - 2, j - 1, n - 1)
+ findPos(i - 2, j + 1, n - 1)
+ findPos(i - 1, j + 2, n - 1)
+ findPos(i + 1, j + 2, n - 1)
+ findPos(i + 2, j + 1, n - 1)
+ findPos(i + 2, j - 1, n - 1)
+ findPos(i + 1, j - 2, n - 1);
}
}
}
}
或者,你可以使用BFS算法来轻松实现这一点。要了解有关BFS算法的更多信息,可以使用这个网站。代码中有详细的说明。(很抱歉使用了C++而不是Java,希望你能理解主要内容)
以下是如何执行这个过程的示例代码:
#include<bits/stdc++.h>
using namespace std;
//此数组用于检查位置是否已访问
bool visited[8][8];
//这里创建了一个表示骑士移动方向的数组
int row[] = {-2,-1,+1,+2,+2,+1,-1,-2};
int col[] = {+1,+2,+2,+1,-1,-2,-2,-1};
//根据当前位置和移动编号返回下一个移动
pair<int,int> nextMove(pair<int,int> curPos, int moveNo) {
return {
curPos.first+row[moveNo],
curPos.second+col[moveNo]
};
}
//检查当前位置是否在棋盘上
bool validity(pair<int,int> curPos) {
if(curPos.first<1 || curPos.first>8) return false;
if(curPos.second<1 || curPos.second>8) return false;
return true;
}
//BFS算法
string bfs(pair<int,int> curPos, int n) {
//创建表示已访问位置的字符串表示
string ans = "("+to_string(curPos.first)+","+to_string(curPos.second)+")";
queue<pair<int,int>> q;
q.push(curPos);
//维护级别,以防它超过给定的移动次数“n”
map<pair<int,int>, int> level;
level[curPos] = 0;
visited[curPos.first][curPos.second] = true;
while(!q.empty()) {
curPos = q.front();
if(level[curPos]>=n) break;
q.pop();
for(int i=0; i<8; i++) {
pair<int,int> tempPos = nextMove(curPos,i);
if(validity(tempPos) && !visited[tempPos.first][tempPos.second]) {
level[tempPos] = level[curPos]+1;
q.push(tempPos);
visited[tempPos.first][tempPos.second] = true;
ans += "("+to_string(tempPos.first)+","+to_string(tempPos.second)+")";
}
}
}
return ans;
}
int main() {
ios_base::sync_with_stdio(false);
int i,j,n;
cin >> i >> j >> n;
cout << bfs({i,j},n) << "\n";
}
示例输入:
1 1 2
示例输出:
(1,1)(2,3)(3,2)(1,5)(3,5)(4,4)(4,2)(3,1)(1,3)(2,4)(5,3)(5,1)
英文:
In your code you use a boolean array to keep the visited positions marked and prevent that position from being called again.
Here's the modification:
static boolean visited[][] = new boolean[9][9];
public static String findPos(int i, int j, int n) {
if(i<1 || i>8 || j<1 || j>8 || visited[i][j]) return "";
else {
visited[i][j] = true;
if (n == 0) {
if (i >= 1 && j >= 1 && i <= 8 && j <= 8) {
return "(" + i + ", " + j + " )";
} else {
return "";
}
} else {
if (i >= 1 && j >= 1 && i <= 8 && j <= 8) {
return "(" + i + ", " + j + " )" + findPos(i - 1, j - 2, n - 1)
+ findPos(i - 2, j - 1, n - 1)
+ findPos(i - 2, j + 1, n - 1)
+ findPos(i - 1, j + 2, n - 1)
+ findPos(i + 1, j + 2, n - 1)
+ findPos(i + 2, j + 1, n - 1)
+ findPos(i + 2, j - 1, n - 1)
+ findPos(i + 1, j - 2, n - 1);
} else {
return findPos(i - 1, j - 2, n - 1)
+ findPos(i - 2, j - 1, n - 1)
+ findPos(i - 2, j + 1, n - 1)
+ findPos(i - 1, j + 2, n - 1)
+ findPos(i + 1, j + 2, n - 1)
+ findPos(i + 2, j + 1, n - 1)
+ findPos(i + 2, j - 1, n - 1)
+ findPos(i + 1, j - 2, n - 1);
}
}
}
}
Or, you could use the BFS algorithm to achieve this quite easily. To know more about the BFS algorithm, you can use this site. Details are in the code.(Apologies for using C++ instead of Java, I hope you'll be able to get the gist)
Here's how you can do this-
#include<bits/stdc++.h>
using namespace std;
//This array is to check if a position is visited or not
bool visited[8][8];
//Here you're making a direction array for the move of the knight
int row[] = {-2,-1,+1,+2,+2,+1,-1,-2};
int col[] = {+1,+2,+2,+1,-1,-2,-2,-1};
//Returning the next move based on the current position and the move no
pair<int,int> nextMove(pair<int,int> curPos, int moveNo) {
return {
curPos.first+row[moveNo],
curPos.second+col[moveNo]
};
}
//Checking if the current position is in the board or not
bool validity(pair<int,int> curPos) {
if(curPos.first<1 || curPos.first>8) return false;
if(curPos.second<1 || curPos.second>8) return false;
return true;
}
//BFS algorithm
string bfs(pair<int,int> curPos, int n) {
//Making the string representation of the visited positions
string ans = "("+to_string(curPos.first)+","+to_string(curPos.second)+")";
queue<pair<int,int>> q;
q.push(curPos);
//Maintaining level so that it doesn't exceed the given "n" number of moves
map<pair<int,int>, int> level;
level[curPos] = 0;
visited[curPos.first][curPos.second] = true;
while(!q.empty()) {
curPos = q.front();
if(level[curPos]>=n) break;
q.pop();
for(int i=0; i<8; i++) {
pair<int,int> tempPos = nextMove(curPos,i);
if(validity(tempPos) && !visited[tempPos.first][tempPos.second]) {
level[tempPos] = level[curPos]+1;
q.push(tempPos);
visited[tempPos.first][tempPos.second] = true;
ans += "("+to_string(tempPos.first)+","+to_string(tempPos.second)+")";
}
}
}
return ans;
}
int main() {
ios_base::sync_with_stdio(false);
int i,j,n;
cin >> i >> j >> n;
cout << bfs({i,j},n) << "\n";
}
Sample input:
1 1 2
Sample output:
(1,1)(2,3)(3,2)(1,5)(3,5)(4,4)(4,2)(3,1)(1,3)(2,4)(5,3)(5,1)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论