当前位置:首页 > 技术 > 正文内容

最长子序列问题的动态规划解法

访客 技术 2026年8月30日 1
动态规划是解决子序列问题的有效方法,以下是几种常见子序列问题的解决方案。

最长递增子序列

给定一个数值序列,寻找最长的递增子序列,元素不一定连续。

#include <cstdio>
#include <algorithm>
using namespace std;
const int MAX_N = 1001;
int main() {
    int n;
    scanf("%d", &n);
    int maxLen = 1;
    int dp[MAX_N];
    int arr[MAX_N];
    for (int i = 0; i < n; i++) {
        scanf("%d", &arr[i]);
        dp[i] = 1;
        for (int j = 0; j < i; j++) {
            if (arr[j] < arr[i]) {
                dp[i] = max(dp[i], dp[j] + 1);
            }
        }
        maxLen = max(maxLen, dp[i]);
    }
    printf("%d\n", maxLen);
    return 0;
}

修改比较条件可实现其他变体:

  • 最长不降子序列:arr[j] ≤ arr[i]
  • 最长递减子序列:arr[j] > arr[i]
  • 最长不升子序列:arr[j] ≥ arr[i]

木棍加工问题

处理n个木棍,每个有长度和重量。机器设置时间取决于前后木棍的尺寸关系,求最小设置时间。

#include <cstdio>
#include <algorithm>
using namespace std;
const int MAX_STICKS = 5001;
int main() {
    int testCases;
    scanf("%d", &testCases);
    while (testCases--) {
        int n;
        scanf("%d", &n);
        pair<int, int> sticks[MAX_STICKS];
        for (int i = 0; i < n; i++) {
            scanf("%d%d", &sticks[i].first, &sticks[i].second);
        }
        sort(sticks, sticks + n);
        int count = 0;
        int seq[MAX_STICKS];
        for (int i = 0; i < n; i++) {
            int left = -1;
            int right = count;
            while (right - left > 1) {
                int mid = (left + right) / 2;
                if (seq[mid] > sticks[i].second) {
                    left = mid;
                } else {
                    right = mid;
                }
            }
            seq[right] = sticks[i].second;
            if (right == count) {
                count++;
            }
        }
        printf("%d\n", count);
    }
    return 0;
}

士兵队列问题

调整士兵队列,使得每个士兵至少能看到一侧的尽头,求最少需要移除的士兵数。

#include <cstdio>
#include <algorithm>
using namespace std;
const int MAX_SOLDIERS = 1005;
int main() {
    double heights[MAX_SOLDIERS];
    int n;
    scanf("%d", &n);
    int leftDP[MAX_SOLDIERS], rightDP[MAX_SOLDIERS];
    for (int i = 0; i < n; i++) {
        scanf("%lf", &heights[i]);
        leftDP[i] = 1;
        for (int j = 0; j < i; j++) {
            if (heights[j] < heights[i]) {
                leftDP[i] = max(leftDP[i], leftDP[j] + 1);
            }
        }
    }
    for (int i = n - 1; i >= 0; i--) {
        rightDP[i] = 1;
        for (int j = n - 1; j > i; j--) {
            if (heights[j] < heights[i]) {
                rightDP[i] = max(rightDP[i], rightDP[j] + 1);
            }
        }
    }
    int maxRemain = 1;
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            maxRemain = max(maxRemain, leftDP[i] + rightDP[j]);
        }
    }
    printf("%d\n", n - maxRemain);
    return 0;
}

最大子数组和

寻找数列中两个不重叠的连续子数组,使它们的和最大。

#include <cstdio>
#include <algorithm>
using namespace std;
const int MAX_LEN = 50005;
const int MIN_VAL = -10000;
int main() {
    int tests;
    scanf("%d", &tests);
    while (tests--) {
        int n;
        scanf("%d", &n);
        int leftMax[MAX_LEN], rightMax[MAX_LEN];
        leftMax[0] = rightMax[n + 1] = MIN_VAL;
        int arr[MAX_LEN];
        for (int i = 0; i < n; i++) {
            scanf("%d", &arr[i]);
            leftMax[i + 1] = max(arr[i], leftMax[i] + arr[i]);
        }
        for (int i = 1; i <= n; i++) {
            leftMax[i] = max(leftMax[i - 1], leftMax[i]);
        }
        for (int i = n; i > 0; i--) {
            rightMax[i] = max(arr[i - 1], rightMax[i + 1] + arr[i - 1]);
        }
        for (int i = n; i > 0; i--) {
            rightMax[i] = max(rightMax[i + 1], rightMax[i]);
        }
        int result = MIN_VAL;
        for (int i = 1; i < n; i++) {
            result = max(result, leftMax[i] + rightMax[i + 1]);
        }
        printf("%d\n", result);
    }
    return 0;
}

最大子矩阵和

在二维矩阵中寻找元素和最大的子矩阵。

#include <cstdio>
#include <algorithm>
using namespace std;
int main() {
    int bestSum = -128;
    int matrix[101][101] = {0};
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            int value;
            scanf("%d", &value);
            matrix[i][j] = matrix[i][j - 1] + value;
        }
    }
    for (int endCol = 1; endCol <= n; endCol++) {
        for (int startCol = 0; startCol < endCol; startCol++) {
            for (int row = 1, currentSum = 0; row <= n; row++) {
                int colSum = matrix[row][endCol] - matrix[row][startCol];
                currentSum = colSum + max(0, currentSum);
                bestSum = max(bestSum, currentSum);
            }
        }
    }
    printf("%d\n", bestSum);
    return 0;
}

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

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