pull/944/head
krahets 1 year ago
parent a04196b789
commit 562ca7dc89

@ -40,9 +40,9 @@ comments: true
那么,如何处理对角线约束呢?设棋盘中某个格子的行列索引为 $(row, col)$ ,选定矩阵中的某条主对角线,我们发现该对角线上所有格子的行索引减列索引都相等,**即对角线上所有格子的 $row - col$ 为恒定值**。
也就是说,如果两个格子满足 $row_1 - col_1 = row_2 - col_2$ ,则它们一定处在同一条主对角线上。利用该规律,我们可以借助图 13-18 所示的数组 `diag1` ,记录每条主对角线上是否有皇后。
也就是说,如果两个格子满足 $row_1 - col_1 = row_2 - col_2$ ,则它们一定处在同一条主对角线上。利用该规律,我们可以借助图 13-18 所示的数组 `diags1` ,记录每条主对角线上是否有皇后。
同理,**次对角线上的所有格子的 $row + col$ 是恒定值**。我们同样也可以借助数组 `diag2` 来处理次对角线约束。
同理,**次对角线上的所有格子的 $row + col$ 是恒定值**。我们同样也可以借助数组 `diags2` 来处理次对角线约束。
![处理列约束和对角线约束](n_queens_problem.assets/n_queens_cols_diagonals.png)
@ -50,7 +50,7 @@ comments: true
### 3.   代码实现
请注意,$n$ 维方阵中 $row - col$ 的范围是 $[-n + 1, n - 1]$ $row + col$ 的范围是 $[0, 2n - 2]$ ,所以主对角线和次对角线的数量都为 $2n - 1$ ,即数组 `diag1` 和 `diag2` 的长度都为 $2n - 1$ 。
请注意,$n$ 维方阵中 $row - col$ 的范围是 $[-n + 1, n - 1]$ $row + col$ 的范围是 $[0, 2n - 2]$ ,所以主对角线和次对角线的数量都为 $2n - 1$ ,即数组 `diags1` 和 `diags2` 的长度都为 $2n - 1$ 。
=== "Python"

@ -388,7 +388,7 @@ comments: true
}
```
`while` 循环中,由于初始化和更新条件变量的步骤是独立在循环结构之外的,**因此它比 `for` 循环的自由度更高**
**`while` 循环比 `for` 循环的自由度更高**。在 `while` 循环中,我们可以自由设计条件变量的初始化和更新步骤
例如在以下代码中,条件变量 $i$ 每轮进行了两次更新,这种情况就不太方便用 `for` 循环实现。

@ -725,7 +725,7 @@ $$
for i in range(1, n + 1):
for a in range(1, amt + 1):
if coins[i - 1] > a:
# 若超过背包容量,则不选硬币 i
# 若超过目标金额,则不选硬币 i
dp[i][a] = dp[i - 1][a]
else:
# 不选和选硬币 i 这两种方案的较小值
@ -750,7 +750,7 @@ $$
for (int i = 1; i <= n; i++) {
for (int a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[i][a] = dp[i - 1][a];
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -779,7 +779,7 @@ $$
for (int i = 1; i <= n; i++) {
for (int a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[i][a] = dp[i - 1][a];
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -808,7 +808,7 @@ $$
for (int i = 1; i <= n; i++) {
for (int a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[i, a] = dp[i - 1, a];
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -840,7 +840,7 @@ $$
for i := 1; i <= n; i++ {
for a := 1; a <= amt; a++ {
if coins[i-1] > a {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[i][a] = dp[i-1][a]
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -872,7 +872,7 @@ $$
for i in stride(from: 1, through: n, by: 1) {
for a in stride(from: 1, through: amt, by: 1) {
if coins[i - 1] > a {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[i][a] = dp[i - 1][a]
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -903,7 +903,7 @@ $$
for (let i = 1; i <= n; i++) {
for (let a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[i][a] = dp[i - 1][a];
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -934,7 +934,7 @@ $$
for (let i = 1; i <= n; i++) {
for (let a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[i][a] = dp[i - 1][a];
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -963,7 +963,7 @@ $$
for (int i = 1; i <= n; i++) {
for (int a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[i][a] = dp[i - 1][a];
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -992,7 +992,7 @@ $$
for i in 1..=n {
for a in 1..=amt {
if coins[i - 1] > a as i32 {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[i][a] = dp[i - 1][a];
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -1022,7 +1022,7 @@ $$
for (int i = 1; i <= n; i++) {
for (int a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[i][a] = dp[i - 1][a];
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -1051,7 +1051,7 @@ $$
for (1..n + 1) |i| {
for (1..amt + 1) |a| {
if (coins[i - 1] > @as(i32, @intCast(a))) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[i][a] = dp[i - 1][a];
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -1135,7 +1135,7 @@ $$
# 正序遍历
for a in range(1, amt + 1):
if coins[i - 1] > a:
# 若超过背包容量,则不选硬币 i
# 若超过目标金额,则不选硬币 i
dp[a] = dp[a]
else:
# 不选和选硬币 i 这两种方案的较小值
@ -1157,7 +1157,7 @@ $$
for (int i = 1; i <= n; i++) {
for (int a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[a] = dp[a];
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -1184,7 +1184,7 @@ $$
for (int i = 1; i <= n; i++) {
for (int a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[a] = dp[a];
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -1211,7 +1211,7 @@ $$
for (int i = 1; i <= n; i++) {
for (int a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[a] = dp[a];
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -1240,7 +1240,7 @@ $$
// 倒序遍历
for a := 1; a <= amt; a++ {
if coins[i-1] > a {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[a] = dp[a]
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -1269,7 +1269,7 @@ $$
for i in stride(from: 1, through: n, by: 1) {
for a in stride(from: 1, through: amt, by: 1) {
if coins[i - 1] > a {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[a] = dp[a]
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -1295,7 +1295,7 @@ $$
for (let i = 1; i <= n; i++) {
for (let a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[a] = dp[a];
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -1321,7 +1321,7 @@ $$
for (let i = 1; i <= n; i++) {
for (let a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[a] = dp[a];
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -1347,7 +1347,7 @@ $$
for (int i = 1; i <= n; i++) {
for (int a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[a] = dp[a];
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -1374,7 +1374,7 @@ $$
for i in 1..=n {
for a in 1..=amt {
if coins[i - 1] > a as i32 {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[a] = dp[a];
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -1401,7 +1401,7 @@ $$
for (int i = 1; i <= n; i++) {
for (int a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[a] = dp[a];
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -1428,7 +1428,7 @@ $$
for (1..n + 1) |i| {
for (1..amt + 1) |a| {
if (coins[i - 1] > @as(i32, @intCast(a))) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[a] = dp[a];
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -1483,7 +1483,7 @@ $$
for i in range(1, n + 1):
for a in range(1, amt + 1):
if coins[i - 1] > a:
# 若超过背包容量,则不选硬币 i
# 若超过目标金额,则不选硬币 i
dp[i][a] = dp[i - 1][a]
else:
# 不选和选硬币 i 这两种方案之和
@ -1507,7 +1507,7 @@ $$
for (int i = 1; i <= n; i++) {
for (int a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[i][a] = dp[i - 1][a];
} else {
// 不选和选硬币 i 这两种方案之和
@ -1535,7 +1535,7 @@ $$
for (int i = 1; i <= n; i++) {
for (int a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[i][a] = dp[i - 1][a];
} else {
// 不选和选硬币 i 这两种方案之和
@ -1563,7 +1563,7 @@ $$
for (int i = 1; i <= n; i++) {
for (int a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[i, a] = dp[i - 1, a];
} else {
// 不选和选硬币 i 这两种方案之和
@ -1594,7 +1594,7 @@ $$
for i := 1; i <= n; i++ {
for a := 1; a <= amt; a++ {
if coins[i-1] > a {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[i][a] = dp[i-1][a]
} else {
// 不选和选硬币 i 这两种方案之和
@ -1622,7 +1622,7 @@ $$
for i in stride(from: 1, through: n, by: 1) {
for a in stride(from: 1, through: amt, by: 1) {
if coins[i - 1] > a {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[i][a] = dp[i - 1][a]
} else {
// 不选和选硬币 i 这两种方案之和
@ -1652,7 +1652,7 @@ $$
for (let i = 1; i <= n; i++) {
for (let a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[i][a] = dp[i - 1][a];
} else {
// 不选和选硬币 i 这两种方案之和
@ -1682,7 +1682,7 @@ $$
for (let i = 1; i <= n; i++) {
for (let a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[i][a] = dp[i - 1][a];
} else {
// 不选和选硬币 i 这两种方案之和
@ -1710,7 +1710,7 @@ $$
for (int i = 1; i <= n; i++) {
for (int a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[i][a] = dp[i - 1][a];
} else {
// 不选和选硬币 i 这两种方案之和
@ -1738,7 +1738,7 @@ $$
for i in 1..=n {
for a in 1..=amt {
if coins[i - 1] > a as i32 {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[i][a] = dp[i - 1][a];
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -1767,7 +1767,7 @@ $$
for (int i = 1; i <= n; i++) {
for (int a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[i][a] = dp[i - 1][a];
} else {
// 不选和选硬币 i 这两种方案之和
@ -1795,7 +1795,7 @@ $$
for (1..n + 1) |i| {
for (1..amt + 1) |a| {
if (coins[i - 1] > @as(i32, @intCast(a))) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[i][a] = dp[i - 1][a];
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -1825,7 +1825,7 @@ $$
# 正序遍历
for a in range(1, amt + 1):
if coins[i - 1] > a:
# 若超过背包容量,则不选硬币 i
# 若超过目标金额,则不选硬币 i
dp[a] = dp[a]
else:
# 不选和选硬币 i 这两种方案之和
@ -1846,7 +1846,7 @@ $$
for (int i = 1; i <= n; i++) {
for (int a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[a] = dp[a];
} else {
// 不选和选硬币 i 这两种方案之和
@ -1871,7 +1871,7 @@ $$
for (int i = 1; i <= n; i++) {
for (int a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[a] = dp[a];
} else {
// 不选和选硬币 i 这两种方案之和
@ -1896,7 +1896,7 @@ $$
for (int i = 1; i <= n; i++) {
for (int a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[a] = dp[a];
} else {
// 不选和选硬币 i 这两种方案之和
@ -1922,7 +1922,7 @@ $$
// 倒序遍历
for a := 1; a <= amt; a++ {
if coins[i-1] > a {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[a] = dp[a]
} else {
// 不选和选硬币 i 这两种方案之和
@ -1947,7 +1947,7 @@ $$
for i in stride(from: 1, through: n, by: 1) {
for a in stride(from: 1, through: amt, by: 1) {
if coins[i - 1] > a {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[a] = dp[a]
} else {
// 不选和选硬币 i 这两种方案之和
@ -1972,7 +1972,7 @@ $$
for (let i = 1; i <= n; i++) {
for (let a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[a] = dp[a];
} else {
// 不选和选硬币 i 这两种方案之和
@ -1997,7 +1997,7 @@ $$
for (let i = 1; i <= n; i++) {
for (let a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[a] = dp[a];
} else {
// 不选和选硬币 i 这两种方案之和
@ -2022,7 +2022,7 @@ $$
for (int i = 1; i <= n; i++) {
for (int a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[a] = dp[a];
} else {
// 不选和选硬币 i 这两种方案之和
@ -2047,7 +2047,7 @@ $$
for i in 1..=n {
for a in 1..=amt {
if coins[i - 1] > a as i32 {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[a] = dp[a];
} else {
// 不选和选硬币 i 这两种方案的较小值
@ -2073,7 +2073,7 @@ $$
for (int i = 1; i <= n; i++) {
for (int a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[a] = dp[a];
} else {
// 不选和选硬币 i 这两种方案之和
@ -2098,7 +2098,7 @@ $$
for (1..n + 1) |i| {
for (1..amt + 1) |a| {
if (coins[i - 1] > @as(i32, @intCast(a))) {
// 若超过背包容量,则不选硬币 i
// 若超过目标金额,则不选硬币 i
dp[a] = dp[a];
} else {
// 不选和选硬币 i 这两种方案的较小值

Loading…
Cancel
Save