为什么 "if" 不起作用? (n 皇后问题)
Why the "if" didn't work ? (n queen problem)
这是我的代码
#include <iostream>
#include <vector>
using namespace std;
int k = 4;
vector<int> QLocation(k,0);
vector<vector<string> > board(k, vector<string>(k, "."));
bool check(int row, int column)
{
if (row == 0) return true;
for (int m = row - 1, n = 1; m >= 0; m--, n++)
{
if (board[m][column] == "Q") return false;
if (column + n < n && board[m][column + n] == "Q") return false;
if (column - n >= 0 && board[m][column - n] == "Q") return false;
}
return true;
}
void solve(int row, int column)
{
for (int i = row; i < k;i++)
{
for (int j = column; j < k; j++)
{
if (check(i, j))
{
board[i][j] = "Q";
QLocation[i] = j;
break;
}
else
board[i][j] = ".";
if (j == k - 1)
{
i -= 1;
j = QLocation[i];
}
}
}
}
int main()
{
solve(0, 0);
for (int i = 0; i < k; i++)
{
for (int j = 0; j < k; j++)
cout << board[i][j];
cout << endl;
}
}
输出是无限循环
我在第11、15、16、17、28行设置断点,一步步查看值的变化
当i=2,j=1时,输入check当m=1,n=1时,board[m][column + n] == "Q"但不returnfalse
为什么?
====== 2021/08/25 22:00更新======
当我删除这些代码并且 k=4
if (j == k - 1)
{
i -= 1;
j = QLocation[i];
}
输出是
Q...
..Q.
.Q..
....
当k=8时输出为
Q.......
..Q.....
.Q......
.....Q..
.......Q
...Q....
........
....Q...
第三行总是失败,但其他行都是正确的
你的问题我觉得是这个逻辑。
for (int m = row - 1, n = 1; m >= 0; m--, n++)
您正在检查 m
何时等于或大于 0。但是您从 -1 开始并在每次迭代中减去 1。这意味着除非 returned.
否则你永远不会停止
而且我猜 m
对于 board[m][column]
没有 board[-10][5]
而它可能有 board[10][5]
。所以你永远不会return false.
天哪……我的眼睛坏了。虽然查了很多遍,还是没有找到第16行
if (column + n <n && board[m][column + n] == "Q") return false;
column + n < n
应该改为column + n < k
感谢molbdnilo,很抱歉浪费大家的时间
====== 2021/08/26 00:05更新======
我终于修好了,这是代码
(我知道它很丑并且有异常(比如 k=3)和多个解决方案(比如 k=4 有两个解决方案)要处理)
#include <iostream>
#include <vector>
using namespace std;
int k = 4;
vector<int> QLocation(k,0);
vector<vector<string> > board(k, vector<string>(k, "."));
bool check(int row, int column)
{
if (row == 0) return true;
for (int m = row - 1, n = 1; m >= 0; m--, n++)
{
if (board[m][column] == "Q") return false;
if (column + n < k && board[m][column + n] == "Q") return false;
if (column - n >= 0 && board[m][column - n] == "Q") return false;
}
return true;
}
void solve(int row, int column)
{
bool rowFail = false;
for (int i = row; i < k; i++)
{
for (int j = column; j < k; j++)
{
if (check(i, j))
{
board[i][j] = "Q";
QLocation[i] = j;
rowFail = false;
break;
}
else
{
board[i][j] = ".";
rowFail = true;
}
}
if (rowFail)
{
column = QLocation[i -= 1];
board[i][column] = ".";
i -= 1;
column += 1;
}
else
column = 0;
}
}
int main()
{
solve(0, 0);
for (int x = 0; x < k; x++)
{
for (int y = 0; y < k; y++)
cout << board[x][y];
cout << endl;
}
}
编辑:此答案假定您已将 if(column + n < n ...)
中的拼写错误更正为 if(column + n < k ...)
问题出在这部分
if(j == k-1){
i -= 1;
j = Qlocation[i];
}
考虑迭代中k = 4和i = 2的情况。届时董事会将看起来像这样。
Q...
..Q.
....
....
这里 check(i, j)
对于 i = 2 总是假的,所以 i
回到 1。但是你没有改变 board[i][Qlocation[i]] 的值回来到 '。'。这是一个错误(即使你更正了这个,它也不会起作用。我会告诉你为什么假设你通过在 j = Qlocation[i]; 之后添加 board[i][j] = "." 来更正它)。现在值是 i = 1,j = 3(for 循环中的 j++)。检查 return 为真,你在那里放置一个皇后,然后 i
增加到 2。
棋盘:
Q...
...Q
....
....
这里,检查 (i, j) returns true for j = 1. The board:
Q...
...Q
.Q..
....
现在 i = 3。check(i, j) 对所有 j 都失败。 i 减少到 2,j 减少到 2(j = Qlocation(i), j++)。 check(i, j) 对于 (2, 2) 和 (2, 3) 失败,在这一点上 i 进一步减少到 1,j 减少到 4 (j = Qlocation(1), j++).
棋盘:
Q...
....
....
....
because of board[i][j] = ".";
现在j = 4不满足条件j < k,所以内层for循环中断,外层for循环迭代增加i
到2。 check(i, j) return j = 1 时为真。棋盘:
Q...
....
.Q..
....
现在 i = 3,check(i, j) 对所有 j 都失败,i 变为 2。check(i, j) returns true for j = 3.The board:
Q...
....
...Q
....
现在再次 i = 3,检查 (i, j) return对于 j = 1 为真。最终答案:
Q...
....
...Q
.Q..
这是错误的。因此,您必须添加一个检查 for 循环是否在行中没有任何 Q 的情况下退出。
这是我的代码
#include <iostream>
#include <vector>
using namespace std;
int k = 4;
vector<int> QLocation(k,0);
vector<vector<string> > board(k, vector<string>(k, "."));
bool check(int row, int column)
{
if (row == 0) return true;
for (int m = row - 1, n = 1; m >= 0; m--, n++)
{
if (board[m][column] == "Q") return false;
if (column + n < n && board[m][column + n] == "Q") return false;
if (column - n >= 0 && board[m][column - n] == "Q") return false;
}
return true;
}
void solve(int row, int column)
{
for (int i = row; i < k;i++)
{
for (int j = column; j < k; j++)
{
if (check(i, j))
{
board[i][j] = "Q";
QLocation[i] = j;
break;
}
else
board[i][j] = ".";
if (j == k - 1)
{
i -= 1;
j = QLocation[i];
}
}
}
}
int main()
{
solve(0, 0);
for (int i = 0; i < k; i++)
{
for (int j = 0; j < k; j++)
cout << board[i][j];
cout << endl;
}
}
输出是无限循环
我在第11、15、16、17、28行设置断点,一步步查看值的变化
当i=2,j=1时,输入check当m=1,n=1时,board[m][column + n] == "Q"但不returnfalse
为什么?
====== 2021/08/25 22:00更新======
当我删除这些代码并且 k=4
if (j == k - 1)
{
i -= 1;
j = QLocation[i];
}
输出是
Q...
..Q.
.Q..
....
当k=8时输出为
Q.......
..Q.....
.Q......
.....Q..
.......Q
...Q....
........
....Q...
第三行总是失败,但其他行都是正确的
你的问题我觉得是这个逻辑。
for (int m = row - 1, n = 1; m >= 0; m--, n++)
您正在检查 m
何时等于或大于 0。但是您从 -1 开始并在每次迭代中减去 1。这意味着除非 returned.
而且我猜 m
对于 board[m][column]
没有 board[-10][5]
而它可能有 board[10][5]
。所以你永远不会return false.
天哪……我的眼睛坏了。虽然查了很多遍,还是没有找到第16行
if (column + n <n && board[m][column + n] == "Q") return false;
column + n < n
应该改为column + n < k
感谢molbdnilo,很抱歉浪费大家的时间
====== 2021/08/26 00:05更新======
我终于修好了,这是代码
(我知道它很丑并且有异常(比如 k=3)和多个解决方案(比如 k=4 有两个解决方案)要处理)
#include <iostream>
#include <vector>
using namespace std;
int k = 4;
vector<int> QLocation(k,0);
vector<vector<string> > board(k, vector<string>(k, "."));
bool check(int row, int column)
{
if (row == 0) return true;
for (int m = row - 1, n = 1; m >= 0; m--, n++)
{
if (board[m][column] == "Q") return false;
if (column + n < k && board[m][column + n] == "Q") return false;
if (column - n >= 0 && board[m][column - n] == "Q") return false;
}
return true;
}
void solve(int row, int column)
{
bool rowFail = false;
for (int i = row; i < k; i++)
{
for (int j = column; j < k; j++)
{
if (check(i, j))
{
board[i][j] = "Q";
QLocation[i] = j;
rowFail = false;
break;
}
else
{
board[i][j] = ".";
rowFail = true;
}
}
if (rowFail)
{
column = QLocation[i -= 1];
board[i][column] = ".";
i -= 1;
column += 1;
}
else
column = 0;
}
}
int main()
{
solve(0, 0);
for (int x = 0; x < k; x++)
{
for (int y = 0; y < k; y++)
cout << board[x][y];
cout << endl;
}
}
编辑:此答案假定您已将 if(column + n < n ...)
中的拼写错误更正为 if(column + n < k ...)
问题出在这部分
if(j == k-1){
i -= 1;
j = Qlocation[i];
}
考虑迭代中k = 4和i = 2的情况。届时董事会将看起来像这样。
Q...
..Q.
....
....
这里 check(i, j)
对于 i = 2 总是假的,所以 i
回到 1。但是你没有改变 board[i][Qlocation[i]] 的值回来到 '。'。这是一个错误(即使你更正了这个,它也不会起作用。我会告诉你为什么假设你通过在 j = Qlocation[i]; 之后添加 board[i][j] = "." 来更正它)。现在值是 i = 1,j = 3(for 循环中的 j++)。检查 return 为真,你在那里放置一个皇后,然后 i
增加到 2。
棋盘:
Q...
...Q
....
....
这里,检查 (i, j) returns true for j = 1. The board:
Q...
...Q
.Q..
....
现在 i = 3。check(i, j) 对所有 j 都失败。 i 减少到 2,j 减少到 2(j = Qlocation(i), j++)。 check(i, j) 对于 (2, 2) 和 (2, 3) 失败,在这一点上 i 进一步减少到 1,j 减少到 4 (j = Qlocation(1), j++).
棋盘:
Q...
....
....
....
because of board[i][j] = ".";
现在j = 4不满足条件j < k,所以内层for循环中断,外层for循环迭代增加i
到2。 check(i, j) return j = 1 时为真。棋盘:
Q...
....
.Q..
....
现在 i = 3,check(i, j) 对所有 j 都失败,i 变为 2。check(i, j) returns true for j = 3.The board:
Q...
....
...Q
....
现在再次 i = 3,检查 (i, j) return对于 j = 1 为真。最终答案:
Q...
....
...Q
.Q..
这是错误的。因此,您必须添加一个检查 for 循环是否在行中没有任何 Q 的情况下退出。