> 首先要注意,题目中的条件有误,应该是严格大于而不是大于等于。
排序+动态规划(暴力搜索)
首先按照第一个维度将数组从小到大排序,第一个维度相同的,按照第二个维度从小到达排序。这样以来,问题就被转换为最大上升子序列问题。使用动态规划求解即可。
状态定义为:以第i
个元素结尾的上升子序列的最大长度。
下面是第一种动态规划的解法,该解法超时。
#include <vector> #include <iostream> #include <limits.h> #include <functional> #include <algorithm> using namespace std; struct Compare { bool operator () (const vector<int>& item1, const vector<int>& item2) { if (item1[0] == item2[0]) { return item1[1] < item2[1]; } else { return item1[0] < item2[0]; } } }; int main() { int n; cin >> n; vector<vector<int>> items(n, vector<int>(2, 0)); for (int i = 0; i < n; i++) { scanf("%d%d", &items[i][0], &items[i][1]); } sort(items.begin(), items.end(), Compare()); vector<int> dp_table(n, 1); int max_sold = 1; for (int i = 1; i < n; i++) { int current_max_length = 1; int length; for (int j = 0; j < i; j++) { if (items[i][1] <= items[j][1]) { continue; } length = dp_table[j] + 1; if (length > current_max_length) { current_max_length = length; } } if (current_max_length > max_sold) { max_sold = current_max_length; } dp_table[i] = current_max_length; } cout << max_sold << endl; return 0; }
排序+动态规划(二分查找+贪心)
在动态规划中,为了更快地进行查找,需要更改状态定义。将状态dp[i]
定义为长度为i + 1
的上升子序列的尾元素的最小值。在进行状态转移时,比较复杂,建议参考最长上升子序列。
代码如下:
#include <vector> #include <iostream> #include <limits.h> #include <functional> #include <algorithm> using namespace std; struct Compare { bool operator () (const vector<int>& item1, const vector<int>& item2) { if (item1[0] == item2[0]) { return item1[1] < item2[1]; } else { return item1[0] < item2[0]; } } }; int main() { int n; cin >> n; vector<vector<int>> items(n, vector<int>(2, 0)); for (int i = 0; i < n; i++) { scanf("%d%d", &items[i][0], &items[i][1]); } sort(items.begin(), items.end(), Compare()); vector<int> dp_table(n, 0); // dp_table[i]表示长度为i + 1的上升子序列末尾的最小值 dp_table[0] = items[0][1]; int end = 0; for (int i = 1; i < n; i++) { if (items[i][1] > dp_table[end]) { end++; dp_table[end] = items[i][1]; } else { int left = 0; int right = end; while (left < right) { // 在dp_table中查找第一个大于items[i][1]的数 int mid = left + (right - left) / 2; if (items[i][1] > dp_table[mid]) { left = mid + 1; } else { right = mid; } } dp_table[left] = items[i][1]; } } end++; cout << end << endl; return 0; } }