1306最长公共上升子序列 c++ 打印路径
时间: 2025-06-13 20:01:03 浏览: 5
### C++ 实现最长公共上升子序列并打印路径
以下是一个完整的解决方案,包括动态规划算法的实现以及路径打印功能。
#### 动态规划与路径追踪
动态规划数组 `f[i][j]` 表示以序列 `a` 的前 `i` 个元素和序列 `b` 的前 `j` 个元素为范围,并且以 `b[j]` 结尾的最长公共上升子序列的长度。为了记录路径,使用辅助数组 `p[j]` 记录每个状态的前驱位置[^2]。
当 `a[i] == b[j]` 时,通过遍历所有满足 `b[k] < b[j]` 的位置 `k` 来更新当前状态,并同时记录最优前驱位置。最终通过回溯 `p[j]` 数组来构造具体的子序列[^2]。
#### 完整代码实现
以下是包含路径打印功能的完整 C++ 实现:
```cpp
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n, m;
cin >> m; // 序列 b 的长度
vector<int> b(m + 1); // 序列 b
for (int i = 1; i <= m; ++i) cin >> b[i];
cin >> n; // 序列 a 的长度
vector<int> a(n + 1); // 序列 a
for (int i = 1; i <= n; ++i) cin >> a[i];
// 定义 dp 数组
vector<vector<int>> f(n + 1, vector<int>(m + 1, 0));
vector<int> p(m + 1, 0); // 用于记录路径
int ans = 0; // 最长公共上升子序列的长度
int end_pos = 0; // 子序列在 b 中的结束位置
// 动态规划填表
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
if (a[i] == b[j]) {
f[i][j] = 1;
for (int k = 1; k < j; ++k) {
if (b[k] < b[j] && f[i][j] < f[i - 1][k] + 1) {
f[i][j] = f[i - 1][k] + 1;
p[j] = k; // 记录前驱位置
}
}
} else {
f[i][j] = f[i - 1][j];
}
// 更新最大值及对应的结束位置
if (f[i][j] > ans) {
ans = f[i][j];
end_pos = j;
}
}
}
// 输出最长公共上升子序列的长度
cout << ans << "\n";
// 回溯路径并输出具体子序列
stack<int> s;
while (end_pos != 0) {
s.push(b[end_pos]);
end_pos = p[end_pos];
}
while (!s.empty()) {
cout << s.top() << " ";
s.pop();
}
cout << "\n";
return 0;
}
```
#### 代码解析
1. **输入部分**:首先读取两个序列 `a` 和 `b` 的长度及其内容。
2. **动态规划数组初始化**:定义二维数组 `f[i][j]` 和一维数组 `p[j]` 分别存储状态值和路径信息。
3. **状态转移**:
- 当 `a[i] == b[j]` 时,尝试从所有满足 `b[k] < b[j]` 的位置 `k` 更新当前状态,并记录最优前驱位置。
- 如果 `a[i] != b[j]`,则直接继承上一行的状态。
4. **路径回溯**:通过栈结构逆序存储路径,并最终输出具体子序列[^2]。
#### 时间复杂度分析
上述实现的时间复杂度为 \(O(n \times m^2)\),其中 \(n\) 和 \(m\) 分别是序列 `a` 和 `b` 的长度。这是因为对于每个状态 `(i, j)`,需要遍历所有可能的前驱位置 `k` 来更新状态。
如果数据规模较大,可以进一步优化时间复杂度为 \(O(n \times m)\),通过维护一个辅助数组记录当前最优解的位置。
---
####
阅读全文
相关推荐


















