棋盘左上角到右下角方案数(2)

本文探讨了组合数学在解决从左上角到右下角的路径计数问题中的应用,提供了公式C(n+m-2,n-1)表示路径总数,并解释了路径之和的计算公式C(n+m-1,n)-1。此外,阐述了第n行的路径和为C(n+m-1,n),并推荐了Codeforces Global Round 21的E题题解作为进一步阅读资料。

在这里插入图片描述
1.从左上角(1,1)到右下角(n,m)的方案数是C(n + m - 2, n - 1)

2.左上角到右下角的方案数之和是 C(n + m - 1, n)- 1

3.第n行的和是C(n + m - 1, n)

第三点的证明,可以看E题的题解Codeforces Global Round 21 A-E - kilo的文章 - 知乎

以下是使用 C++ 实现计算在一个 `n` 行 `m` 列的棋盘上,从左上角出发,卒每步只能向下或向右移动一格且不能移动到黑色格子上,走到右下角的可行方案数并对 `1e9 + 7` 取模的代码: ```cpp #include <iostream> #include <vector> #define MOD 1000000007 using namespace std; int uniquePathsWithObstacles(int n, int m, vector<pair<int, int>>& blackGrids) { vector<vector<int>> dp(n, vector<int>(m, 0)); vector<vector<bool>> isBlack(n, vector<bool>(m, false)); // 标记黑色格子 for (auto& grid : blackGrids) { int x = grid.first - 1; int y = grid.second - 1; isBlack[x][y] = true; } // 初始化第一行和第一列 if (!isBlack[0][0]) { dp[0][0] = 1; } for (int i = 1; i < n; ++i) { if (!isBlack[i][0]) { dp[i][0] = dp[i - 1][0]; } } for (int j = 1; j < m; ++j) { if (!isBlack[0][j]) { dp[0][j] = dp[0][j - 1]; } } // 动态规划计算方案数 for (int i = 1; i < n; ++i) { for (int j = 1; j < m; ++j) { if (!isBlack[i][j]) { dp[i][j] = (dp[i - 1][j] + dp[i][j - 1]) % MOD; } } } return dp[n - 1][m - 1]; } int main() { int n, m, k; cin >> n >> m >> k; vector<pair<int, int>> blackGrids(k); for (int i = 0; i < k; ++i) { int x, y; cin >> x >> y; blackGrids[i] = {x, y}; } int result = uniquePathsWithObstacles(n, m, blackGrids); cout << result << endl; return 0; } ``` ### 代码解释 1. **初始化**:创建一个 `dp` 二维数组用于存储到达每个格子的方案数,同时创建一个 `isBlack` 二维数组用于标记黑色格子。 2. **标记黑色格子**:将输入的黑色格子坐标标记到 `isBlack` 数组中。 3. **初始化第一行和第一列**:如果起点不是黑色格子,则 `dp[0][0]` 设为 1。对于第一行和第一列的其他格子,如果不是黑色格子,则其方案数等于前一个格子的方案数。 4. **动态规划计算方案数**:对于其他格子,如果不是黑色格子,则其方案数等于上方格子和左方格子的方案数之和,并对 `MOD` 取模。 5. **返回结果**:最终返回 `dp[n - 1][m - 1]`,即到达右下角方案数。 ### 复杂度分析 - **时间复杂度**:$O(nm)$,其中 $n$ 和 $m$ 分别是棋盘的行数和列数。 - **空间复杂度**:$O(nm)$,主要用于存储 `dp` 数组和 `isBlack` 数组。 ### 数据范围适用性 该代码可以处理 30% 数据范围 `1 <= n, m <= 2000, 1 <= k <= 2000` 和 100% 数据范围 `1 <= n, m <= 100000, 1 <= k <= 2000`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值