当前位置:首页 > 入门组 > 2022 CSP-J 上升点序(洛谷P8816)解题报告:动态规划求解最长上升序列

2022 CSP-J 上升点序(洛谷P8816)解题报告:动态规划求解最长上升序列

9个月前 (06-21)

2022 CSP-J 上升点序(洛谷P8816)解题报告:动态规划求解最长上升序列 动态规划 最长上升子序列 算法竞赛  第1张




一、题目解读

2022年CSP-J题目“上升点序”(洛谷P8816)要求给定一个平面点集,每个点的坐标(x,y)均为整数。题目需要构造一个最长的上升序列,序列中相邻点的坐标满足x和y均严格递增。允许使用额外的点(不超过k个)来连接原序列中的点,最终输出最长上升序列的长度。关键点在于如何高效利用额外点来扩展序列,同时保证上升性。

二、解题思路

作者采用动态规划(DP)解决该问题。核心思想是将问题分解为子问题,通过状态转移计算最长序列。定义二维DP数组dp[i][j]表示以第i个点结尾,使用j个额外点时的最长序列长度。通过遍历所有可能的“前驱点”,计算插入额外点的数量,从而更新状态。

三、解题步骤

1. 输入与预处理:读入n个点坐标,按(x,y)升序排序(确保后续DP顺序依赖)。

2. 动态规划初始化:dp[i][j]初始化为1(每个点自身构成长度为1的序列)。

3. 状态转移:

    遍历前驱点prev,若prev在点i的左下方,计算需插入的点数needed = dx + dy - 1(由斜率公式推导)。

    若needed ≤ j,更新dp[i][j] = max(dp[i][j], dp[prev][j-needed] + dx + dy),即利用剩余额外点延长序列。

4. 结果优化:考虑剩余额外点(k-j)对序列的延长,更新全局最大值max_len。

5. 输出结果:最终最长序列长度。

四、代码与注释

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 定义点结构,按(x,y)升序排序
struct Point {
    int x, y;
    bool operator<(const Point& other) const {
        return x < other.x || (x == other.x && y < other.y);
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); // 优化输入输出速度

    int n, k;
    cin >> n >> k;
    
    vector<Point> points(n);
    for (int i = 0; i < n; ++i) {
        cin >> points[i].x >> points[i].y;
    }
    sort(points.begin(), points.end()); // 排序,保证DP顺序依赖

    // dp[i][j]表示以第i个点结尾,使用j个额外点时的最长序列长度
    vector<vector<int>> dp(n, vector<int>(k + 1, 1));
    int max_len = 1;

    for (int i = 0; i < n; ++i) {
        for (int j = 0; j <= k; ++j) {
            dp[i][j] = 1; // 初始化为1(单点序列)
            
            for (int prev = 0; prev < i; ++prev) {
                if (points[prev].x > points[i].x || points[prev].y > points[i].y) {
                    continue; // 跳过非左下方点
                }
                int dx = points[i].x - points[prev].x;
                int dy = points[i].y - points[prev].y;
                int needed = dx + dy - 1; // 计算插入点数
                if (needed <= j) {
                    // 若额外点足够,更新状态
                    dp[i][j] = max(dp[i][j], dp[prev][j - needed] + dx + dy);
                }
            }
            max_len = max(max_len, dp[i][j] + (k - j)); // 考虑剩余额外点延长
        }
    }
    
    cout << max_len << endl;
    return 0;
}

五、总结

该解法巧妙利用动态规划解决带额外点的最长上升序列问题。通过排序预处理、斜率推导的插入点数计算,以及状态转移优化,将复杂问题转化为可迭代的子问题。代码结构清晰,时间复杂度O(n²k),适合竞赛场景。掌握此类DP问题的建模思路,对算法竞赛中类似题目具有重要参考价值。

原创内容 转载请注明出处

分享给朋友:

相关文章

洛谷P1007士兵过桥问题详解 C++贪心算法实现与优化

洛谷P1007士兵过桥问题详解 C++贪心算法实现与优化

题目解读这道题目描述了一座长度为L的桥上有n个士兵,每个士兵每秒可以向左或向右移动1个单位。当士兵到达桥的端点(0或L+1)时离开桥。要求计算所有士兵离开桥的最小时和最大时间。解题思路最小时计算:每个...

CSP-J 2019纪念品题解(洛谷P5662):动态规划+完全背包问题的实战应用

CSP-J 2019纪念品题解(洛谷P5662):动态规划+完全背包问题的实战应用

一、题目解读2019年CSP-J的“纪念品”问题(对应洛谷P5662)要求玩家在T天内通过买卖纪念品最大化金币收益。每天可交易N种商品,需计算最优策略下的最终金币数。题目强调动态规划思维与资源分配优化...

CSP-J方格取数题解|动态规划解法|洛谷P7074代码解析

CSP-J方格取数题解|动态规划解法|洛谷P7074代码解析

一、题目解读题目要求在一个n×m的网格中,从左上角到右下角选择一条路径,路径上的数字可重复取用,求取数之和的最大值。路径限制为仅能向右或向下移动。需注意路径的灵活性与重复取数的可能性,传统单向动态规划...

2024蓝桥杯省赛B组“传送阵”题解(C++代码+图论算法优化)

2024蓝桥杯省赛B组“传送阵”题解(C++代码+图论算法优化)

一、题目解读2024年蓝桥杯省B组“传送阵”题目要求处理一个包含n个节点的图,节点间存在单向传输关系。每个节点i可传送至a[i]指定的节点,形成可能存在的环结构。题目需求解从任意节点出发能到达的最长路...

洛谷P4551题解题报告:图论与Trie树优化异或路径问题的实战解析

洛谷P4551题解题报告:图论与Trie树优化异或路径问题的实战解析

一、题目解读洛谷P4551题要求在一个无向图中,寻找任意两点路径权值异或后的最大值。题目输入为图的边信息(点数n和n-1条边),每条边包含起点、终点及权值。需输出所有路径中权值异或的最大值。问题核心在...

洛谷2789题解:直线交点数的递归求解与优化(附代码详解)

洛谷2789题解:直线交点数的递归求解与优化(附代码详解)

一、题目解读洛谷2789题要求计算n条直线在平面上两两相交时产生的不同交点数量。题目强调“不同”交点,需排除重复情况。解题关键在于如何高效枚举所有可能的交点组合,并避免重复计数。二、解题思路参考代码采...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。