diff --git a/docs/chapter_backtracking/n_queens_problem.md b/docs/chapter_backtracking/n_queens_problem.md index 1c0e81848..475afc8b5 100644 --- a/docs/chapter_backtracking/n_queens_problem.md +++ b/docs/chapter_backtracking/n_queens_problem.md @@ -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" diff --git a/docs/chapter_computational_complexity/iteration_and_recursion.md b/docs/chapter_computational_complexity/iteration_and_recursion.md index f7525d835..69ce4432b 100644 --- a/docs/chapter_computational_complexity/iteration_and_recursion.md +++ b/docs/chapter_computational_complexity/iteration_and_recursion.md @@ -388,7 +388,7 @@ comments: true } ``` -在 `while` 循环中,由于初始化和更新条件变量的步骤是独立在循环结构之外的,**因此它比 `for` 循环的自由度更高**。 +**`while` 循环比 `for` 循环的自由度更高**。在 `while` 循环中,我们可以自由设计条件变量的初始化和更新步骤。 例如在以下代码中,条件变量 $i$ 每轮进行了两次更新,这种情况就不太方便用 `for` 循环实现。 diff --git a/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md b/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md index 5eca339c0..18bb9d9c1 100644 --- a/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md +++ b/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md @@ -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 这两种方案的较小值