当前位置: 首页 > news >正文

P1722 矩阵 II 题解 DFS深度优先遍历与卡特兰数(Catalan number)解

### 题目理解与修改意见:

题目要求我们求解有多少种方式能够在一个 `1 × 2n` 的矩阵中放置红色和黑色算筹,使得矩阵满足“平衡”条件。具体来说,要求:

1. 红色算筹和黑色算筹的数量必须相等。
2. 在前 `i` 格中,红色算筹的数量必须大于或等于黑色算筹的数量。

#### 思路分析:

思路一: dfs 深度优先算法

我们可以将问题视为一种 **合法的括号序列问题**,其中:

* 红色算筹(`r`)充当“左括号”(`(`),
* 黑色算筹(`b`)充当“右括号”(`)`)。

为了保持平衡,我们需要保证在任何前缀中,红色算筹的数量不小于黑色算筹的数量,这正是合法括号序列的条件。最终的合法序列长度为 `2n`,其中红色算筹与黑色算筹数量相等。

#### 关键点:

1. **递归转移**:每次我们可以选择放置红色算筹或者黑色算筹,在放置黑色算筹时,必须保证红色算筹数量大于或等于黑色算筹。
2. **递归中的计数**:使用 DFS 来枚举所有可能的排列,通过动态规划缓存结果,避免重复计算。

#### 问题中的现有代码分析:

* **递归函数 `dfs(m, cnt)`**:递归枚举当前放置的算筹,`m` 是当前的位置,`cnt` 是当前放置的红色算筹的数量。
* **状态转移**:`r++` 表示放置一个红色算筹,`b++` 表示放置一个黑色算筹,满足条件的情况下递归调用。

#### 修改与改进:

根据题目要求,需要根据“红色算筹和黑色算筹数量相等且红色算筹数量不小于黑色算筹数量”的条件来修改现有代码,下面是改进后的实现:

```cpp
#include <bits/stdc++.h>
using namespace std;

int n, v[205][205], r, b;
const int MOD = 100;

int dfs(int m, int cnt) {
// m 代表当前的位置,cnt 代表已经放置的红色算筹的数量
if (m == 2 * n) {  // 如果已经放置了 2n 个算筹,说明完成了一个合法的排列
return (cnt == n);  // 只有当红色算筹数量等于黑色算筹数量时,才是有效的
}

    if (v[m][cnt] != -1) {  // 如果已经计算过,直接返回结果
return v[m][cnt];
}

    v[m][cnt] = 0;  // 初始化

    // 放置红色算筹
if (r < n) {
r++;
v[m][cnt] = (v[m][cnt] + dfs(m + 1, cnt + 1)) % MOD;
r--;
}

    // 放置黑色算筹,条件是红色算筹数量大于等于黑色算筹数量
if (b < n && cnt > b) {
b++;
v[m][cnt] = (v[m][cnt] + dfs(m + 1, cnt)) % MOD;
b--;
}

    return v[m][cnt];
}

int main() {
cin >> n;
memset(v, -1, sizeof(v));  // 初始化缓存数组
cout << dfs(0, 0) << endl;  // 从第 0 个位置开始,已放置的红色算筹数量为 0
return 0;
}
```

### 主要修改与改进:

1. **状态缓存**:`v[m][cnt]` 被初始化为 `-1` 表示尚未计算过,用于动态规划缓存。
2. **放置红色算筹条件**:当 `r < n` 时可以放置红色算筹。
3. **放置黑色算筹条件**:当 `b < n` 且当前黑色算筹数量 `b` 小于红色算筹数量 `cnt` 时可以放置黑色算筹。
4. **终止条件**:当 `m == 2 * n` 时,如果红色和黑色算筹的数量相等,即 `cnt == n`,说明这是一个有效的排列。

### 时间复杂度分析:

* 每个递归状态 `v[m][cnt]` 只会计算一次,因此总体时间复杂度为 O(n^2)。

### 输入输出示例:

#### 输入:

```
2
```

#### 输出:

```
2
```

### 方案解释:

1. 红、黑、红、黑
2. 红、红、黑、黑

这些方案是合法的,满足红色算筹的数量大于等于黑色算筹的数量,最终方案数量对 100 取模后的结果为 `2`。

思路二: 卡特兰数(Catalan number)数列

这个问题可以使用卡特兰数来解决。卡特兰数(Catalan number)是一个数列,它在组合数学中有许多应用,其中一种应用就是计算在给定的条件下,红色和黑色算筹的排列方式。

对于这个问题,我们需要找到一个 1×2n 的矩阵中,红色和黑色算筹数量相等且任意前缀中红色算筹数量不小于黑色算筹数量的排列方式。这正好是卡特兰数的一个经典应用。

第 n 个卡特兰数 \( C_n \) 的公式为:
\[ C_n = \frac{1}{n+1} \binom{2n}{n} \]

我们需要计算 \( C_n \) 并对 100 取模。

### C++ 代码实现

```cpp
#include <iostream>
#include <vector>

using namespace std;

int catalan(int n) {
vector<int> C(n + 1, 0);
C[0] = 1;
C[1] = 1;
for (int i = 2; i <= n; i++) {
for (int j = 0; j < i; j++) {
C[i] = (C[i] + C[j] * C[i - j - 1]) % 100;
}
}
return C[n];
}

int main() {
int n;
cin >> n;
cout << catalan(n) << endl;
return 0;
}
```

### 代码解释

1. **定义卡特兰数数组**:我们使用一个动态规划数组 `C` 来存储卡特兰数,其中 `C[i]` 表示第 i 个卡特兰数。
2. **初始化**:`C[0]` 和 `C[1]` 都初始化为 1,因为 \( C_0 = 1 \) 和 \( C_1 = 1 \)。
3. **动态规划计算**:使用两层循环来计算 `C[i]`,其中外层循环从 2 到 n,内层循环从 0 到 i-1。根据卡特兰数的递推公式 \( C_i = \sum_{j=0}^{i-1} C_j C_{i-j-1} \),我们更新 `C[i]`。
4. **取模**:在计算过程中,我们对 100 取模,以确保结果在 100 以内。
5. **输出结果**:最后输出 `C[n]`,即第 n 个卡特兰数对 100 取模后的结果。

### 样例验证

对于输入 \( n = 2 \):
- `C[0] = 1`
- `C[1] = 1`
- `C[2] = C[0] * C[1] + C[1] * C[0] = 1 * 1 + 1 * 1 = 2`

因此,输出为 2,与题目中的样例一致。

### 时间复杂度

该算法的时间复杂度为 \( O(n^2) \),因为我们需要计算 \( C[i] \) 时,内层循环需要遍历 i 次。

### 空间复杂度

空间复杂度为 \( O(n) \),因为我们使用了一个大小为 \( n+1 \) 的数组来存储卡特兰数。

http://www.lryc.cn/news/584293.html

相关文章:

  • 【WPF实战】MVVM中如何从数据模型反查自定义控件实例(ImageView + Halcon)
  • C++类对象多态底层原理及扩展问题
  • Zotero+zotmoov+坚果云同步
  • 2023年华为杯研究生数学建模竞赛E题脑卒中临床智能分析
  • 我的世界Java版1.21.4的Fabric模组开发教程(十五)方块实体渲染器
  • 北京一家IPO业绩持续性存疑,关联交易频繁独立性堪忧
  • iOS 抓包详细教程:从零搭建、操作到实战调试的全流程指南
  • C++ -- STL -- vector
  • 北斗舞动在线监测装置:电力安全的“智慧守护者”
  • 大健康IP如何借“合规创新”抢占行业新风口|创客匠人
  • 基于Python的程序员数据分析与可视化系统的设计与实现
  • linxu内核的signal fault和arm内核的flault
  • 网络综合实验
  • Flowable21条件事件------------持续更新中
  • 【LeetCode100】--- 2.字母异位词分组【复习回顾】
  • 【LeetCode 热题 100】148. 排序链表——(解法二)分治
  • 数据结构与算法之美:广义表
  • ThinkSound V2版 - 一键给无声视频配音,为AI视频生成匹配音效 支持50系显卡 一键整合包下载
  • LeetCode 1652. 拆炸弹
  • 二分查找篇——寻找旋转排序数组中的最小值【LeetCode】
  • 节点小宝:手机图片备份至电脑功能实测体验
  • 机器学习12——支持向量机中
  • Ubuntu 20.04 下**安装 FFmpeg 5.1
  • Lua嵌入式爬虫实现步骤
  • Redis性能基准测试
  • 观众信息设置与统计(视频高级分析与统计功能)
  • Windows下VScode配置FFmpeg开发环境保姆级教程
  • vue中token的使用与统计实践
  • 机器学习11——支持向量机上
  • 快速合并多个CAD图形为单一PDF文档的方法