目录
- 1.体育课测验(二)
- 1.题目链接
- 2.算法原理详解 && 代码实现
- 2.合唱队形
- 1.题目链接
- 2.算法原理详解 && 代码实现
- 3.宵暗的妖怪
- 1.题目链接
- 2.算法原理详解 && 代码实现
1.体育课测验(二)
1.题目链接
- 体育课测验(二)
2.算法原理详解 && 代码实现
- 说明:单纯积累一题[拓扑排序]用于加强印象
- 能识别模型,并且写出代码
vector<int> findOrder(int n, vector<vector<int> >& groups) { vector<vector<int>> edges(n); vector<int> in(n); // 1.建图 for(auto v : groups) { int a = v[0], b = v[1]; // b -> a edges[b].push_back(a); in[a]++; } // 2.入度为0的点,加入到队列中 queue<int> q; for(int i = 0; i < n; i++) { if(in[i] == 0) { q.push(i); } } // 3.拓扑排序 vector<int> ret; while(q.size()) { int tmp = q.front(); q.pop(); ret.push_back(tmp); for(auto x : edges[tmp]) { if(--in[x] == 0) { q.push(x); } } } if(ret.size() == n) { return ret; } else { return {}; } }
2.合唱队形
1.题目链接
- 合唱队形
2.算法原理详解 && 代码实现
-
问题转化:依次枚举任意位置的同学,将其作为山峰位置,找出最长的
x + y - 1
-
解法:动态规划 -> 最长递增子序列模型
- 状态表示:
dp[i]
:以i
位置为结尾的所有子序列中,最长上升子序列的长度f[i]
:以i
位置同学为结尾的最长上升子序列的长度g[i]
:以i
位置同学为结尾的最长上升子序列的长度(从后向前看)
- 状态转移方程:
#include <iostream> #include <vector> using namespace std; int main() { int n = 0; cin >> n; vector<int> nums(n, 0), f(n, 1), g(n, 1); for(auto& x : nums) { cin >> x; } // 从前向后 for(int i = 0; i < n; i++) { for(int j = 0; j < i; j++) { if(nums[j] < nums[i]) { f[i] = max(f[i], f[j] + 1); } } } // 从后向前 for(int i = n - 1; i >= 0; i--) { for(int j = i + 1; j < n; j++) { if(nums[i] > nums[j]) { g[i] = max(g[i], g[j] + 1); } } } int len = 0; for(int i = 0; i < n; i++) { len = max(len, f[i] + g[i] - 1); } cout << n - len << endl; return 0; }
- 状态表示:
3.宵暗的妖怪
1.题目链接
- 宵暗的妖怪
2.算法原理详解 && 代码实现
- 解法:动态规划 --> 线性DP
-
状态表示:
dp[i]
:从[1, n]
区间内吞噬黑暗,最大的饱食度是多少 -
状态转移方程:
-
初始化:
-
返回值:
dp[n]
#include <iostream> #include <vector> using namespace std; int main() { int n = 0; cin >> n; vector<long long> nums(n + 1, 0), dp(n + 1, 0); for(int i = 1; i <= n; i++) { cin >> nums[i]; } for(int i = 3; i <= n; i++) { dp[i] = max(dp[i - 1], dp[i - 3] + nums[i - 1]); } cout << dp[n] << endl; return 0; }
-