【算法】 线性DP(C/C++)

简介: 【算法】 线性DP(C/C++)

线性动态规划(Linear-DP)是一种动态规划方法,它在状态转移时具有线性的特征。线性DP通常适用于那些线性的问题,它的状态并没有很复杂,一般状态转移方程也很简单,想题的思路也是非常快的。

在线性DP中,状态通常定义为一维数组dp[i],表示目前在第i个阶段(例如数组的第i个元素)的最优解。状态转移方程依赖于前面的若干状态,例如dp[i] = f(dp[i-1], dp[i-2], ...),其中f是某个函数,表示如何从前面的一个或多个状态得到当前状态的最优解。其中一位的状态只是一般的情况,下面例题为四维的情况,但是像这样的四维可谓少之又少。

线性DP的常见问题类型包括:

1. 最长递增子序列(LIS):找到数组中最长递增子序列的长度。这个问题可以通过动态规划来解决,其中dp[i]表示以第i个元素结尾的最长递增子序列的长度 。

2. 最大子数组和:在数组中找到一个具有最大和的连续子数组。这个问题可以通过Kadane算法在线性时间内解决,但也可以用线性DP来解决 。

3. 最长公共子序列(LCS):找到两个字符串的最长公共子序列。这个问题的状态转移方程是dp[i][j] = max(dp[i-1][j], dp[i][j-1], dp[i-1][j-1] + (if s1[i] == s2[j])) 。

4. 数字三角形:给定一个数字三角形,从顶部到底部找到路径,使得路径上的数字总和最大。这个问题可以通过动态规划来解决,其中dp[i][j]表示到达三角形第i行第j列的路径的最大和 。

5. 背包问题:在给定背包容量的情况下,从一组物品中选择一些物品,使得它们的总价值最大。虽然背包问题通常与线性DP无关,但某些背包问题的变体(如0/1背包问题)可以采用线性DP的方法解决。

线性DP问题的关键在于正确定义状态和状态转移方程,以及确定合适的初始条件和边界条件。通过这些定义,可以逐步构建出整个问题的最优解。


原题链接:312. 乌龟棋 - AcWing题库

小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。


乌龟棋的棋盘只有一行,该行有 N 个格子,每个格子上一个分数(非负整数)。


棋盘第 1 格是唯一的起点,第 N 格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。


乌龟棋中共有 M 张爬行卡片,分成 4 种不同的类型(M 张卡片中不一定包含所有 4 种类型的卡片),每种类型的卡片上分别标有 1、2、3、4四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。

游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次

游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到该格子相应的分数。


玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的分数总和。


很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同,小明想要找到一种卡片使用顺序使得最终游戏得分最多。


现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,你能告诉小明,他最多能得到多少分吗?

输入格式

输入文件的每行中两个数之间用一个空格隔开。

第 1 行 2 个正整数 N 和 M,分别表示棋盘格子数和爬行卡片数。

第 2 行 N 个非负整数,a1,a2,……,aN,其中 ai 表示棋盘第 i 个格子上的分数。

第 3 行 M 个整数,b1,b2,……,bM,表示 M 张爬行卡片上的数字。

输入数据保证到达终点时刚好用光 M 张爬行卡片。

输出格式

输出只有 1 行,包含 1 个整数,表示小明最多能得到的分数。

数据范围

1≤N≤350,

1≤M≤120,

0≤ai≤100,

1≤bi≤4,

每种爬行卡片的张数不会超过 40。

输入样例:

9 5
6 10 14 2 8 8 18 5 17
1 3 1 2 1


输出样例:

73

解题思路:

此题标签是线性DP,暴力只可过两个样例点,此题DP状态的定义和描述是四维的定义,f[i][j][k][l]数组表示步数1用了i张步数2用了j张步数3用了k张步数4用了l张所获得最大分数,那么可以枚举步数的每一个状态,数组s统计卡牌步数的个数,最后求一下f[s[1]][s[2]][s[3]][s[4]],既每一张卡牌都用完,那么到达任意一个格子,状态转移可以又四个状态转移过来,f[i][j][k][l]=max(f[i-1][j][k][l],f[i][j-1][k][l],f[i][j][k-1][l],f[i][j][k][l-1])+当前值。即到达f[i][j][k][l],可以先走f[i-1][j][k][l],留一张步数为1的卡牌留到最后使用到达此时的点(1+i+2*j+3*k+4*l),同理f[i][j-1][k][l]为留一张步数为2的卡牌到最后一步使用到达(1+i+2*j+3*k+4*l)点……


代码实现:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N =355,M=45;
int n,m;
int a[N],s[N];//a是分数数组,s[i]表示跳i步卡牌有s[i]张
int f[M][M][M][M];
//f[i][j][k][l]数组表示步数1用了i张步数2用了j张步数3用了k张步数4用了l张所获得最大分数
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=1;i<=m;i++){
        int x;
        cin>>x;
        s[x]++;
    }
    f[0][0][0][0]=a[1];//初始为第一个格子,分数为第一个格子
    for(int A=0;A<=s[1];A++){//分别枚举卡牌1,2,3,4的个数
        for(int B=0;B<=s[2];B++){
            for(int C=0;C<=s[3];C++){
                for(int D=0;D<=s[4];D++){
                    int score=a[1+A+2*B+3*C+4*D];//可以到达点的分数
                    //前一个状态可以由少用1,2,3,4步的一张卡牌转移
                    if(A) f[A][B][C][D]=max(f[A][B][C][D],f[A-1][B][C][D]+score);
                    if(B) f[A][B][C][D]=max(f[A][B][C][D],f[A][B-1][C][D]+score);
                    if(C) f[A][B][C][D]=max(f[A][B][C][D],f[A][B][C-1][D]+score);
                    if(D) f[A][B][C][D]=max(f[A][B][C][D],f[A][B][C][D-1]+score);
                }
            }
        }
    }
    cout<<f[s[1]][s[2]][s[3]][s[4]]<<endl;
    return 0;
}

总结:

此种状态定义博主第一次遇到,最多的也就见过三维解决问题,像李白打酒,这个题状态的定义与描述很难想,开始寻思暴力能不能多拿点分,只能过两个样例,^—^,后来看了y总讲解,才知道用四维去定义,还是要多做题,DP问题只要能找到状态转移方程就基本解决了,博主感觉最难的还是状态的定义与描述。多做题积累经验,文章代码实现或者思路有错误的地方,请各位大佬指出,感激不尽*~*。

执笔至此,感触彼多,全文将至,落笔为终,感谢大家的支持。

相关文章
|
5月前
|
存储 监控 算法
基于 C++ 哈希表算法实现局域网监控电脑屏幕的数据加速机制研究
企业网络安全与办公管理需求日益复杂的学术语境下,局域网监控电脑屏幕作为保障信息安全、规范员工操作的重要手段,已然成为网络安全领域的关键研究对象。其作用类似网络空间中的 “电子眼”,实时捕获每台电脑屏幕上的操作动态。然而,面对海量监控数据,实现高效数据存储与快速检索,已成为提升监控系统性能的核心挑战。本文聚焦于 C++ 语言中的哈希表算法,深入探究其如何成为局域网监控电脑屏幕数据处理的 “加速引擎”,并通过详尽的代码示例,展现其强大功能与应用价值。
111 2
|
7月前
|
存储 负载均衡 算法
基于 C++ 语言的迪杰斯特拉算法在局域网计算机管理中的应用剖析
在局域网计算机管理中,迪杰斯特拉算法用于优化网络路径、分配资源和定位故障节点,确保高效稳定的网络环境。该算法通过计算最短路径,提升数据传输速率与稳定性,实现负载均衡并快速排除故障。C++代码示例展示了其在网络模拟中的应用,为企业信息化建设提供有力支持。
181 15
|
7月前
|
存储 算法 数据处理
公司局域网管理中的哈希表查找优化 C++ 算法探究
在数字化办公环境中,公司局域网管理至关重要。哈希表作为一种高效的数据结构,通过哈希函数将关键值(如IP地址、账号)映射到数组索引,实现快速的插入、删除与查找操作。例如,在员工登录验证和设备信息管理中,哈希表能显著提升效率,避免传统线性查找的低效问题。本文以C++为例,展示了哈希表在局域网管理中的具体应用,包括设备MAC地址与IP分配的存储与查询,并探讨了优化哈希函数和扩容策略,确保网络管理高效准确。
|
3月前
|
存储 监控 算法
基于跳表数据结构的企业局域网监控异常连接实时检测 C++ 算法研究
跳表(Skip List)是一种基于概率的数据结构,适用于企业局域网监控中海量连接记录的高效处理。其通过多层索引机制实现快速查找、插入和删除操作,时间复杂度为 $O(\log n)$,优于链表和平衡树。跳表在异常连接识别、黑名单管理和历史记录溯源等场景中表现出色,具备实现简单、支持范围查询等优势,是企业网络监控中动态数据管理的理想选择。
84 0
|
5月前
|
监控 算法 数据处理
基于 C++ 的 KD 树算法在监控局域网屏幕中的理论剖析与工程实践研究
本文探讨了KD树在局域网屏幕监控中的应用,通过C++实现其构建与查询功能,显著提升多维数据处理效率。KD树作为一种二叉空间划分结构,适用于屏幕图像特征匹配、异常画面检测及数据压缩传输优化等场景。相比传统方法,基于KD树的方案检索效率提升2-3个数量级,但高维数据退化和动态更新等问题仍需进一步研究。未来可通过融合其他数据结构、引入深度学习及开发增量式更新算法等方式优化性能。
146 17
|
4月前
|
机器学习/深度学习 存储 算法
基于 C++ 布隆过滤器算法的局域网上网行为控制:URL 访问过滤的高效实现研究
本文探讨了一种基于布隆过滤器的局域网上网行为控制方法,旨在解决传统黑白名单机制在处理海量URL数据时存储与查询效率低的问题。通过C++实现URL访问过滤功能,实验表明该方法可将内存占用降至传统方案的八分之一,查询速度提升约40%,假阳性率可控。研究为优化企业网络管理提供了新思路,并提出结合机器学习、改进哈希函数及分布式协同等未来优化方向。
92 0
|
6月前
|
存储 监控 算法
基于 C++ 哈希表算法的局域网如何监控电脑技术解析
当代数字化办公与生活环境中,局域网的广泛应用极大地提升了信息交互的效率与便捷性。然而,出于网络安全管理、资源合理分配以及合规性要求等多方面的考量,对局域网内计算机进行有效监控成为一项至关重要的任务。实现局域网内计算机监控,涉及多种数据结构与算法的运用。本文聚焦于 C++ 编程语言中的哈希表算法,深入探讨其在局域网计算机监控场景中的应用,并通过详尽的代码示例进行阐释。
119 4
|
7月前
|
存储 算法 安全
企业员工数据泄露防范策略:基于 C++ 语言的布隆过滤器算法剖析[如何防止员工泄密]
企业运营过程中,防范员工泄密是信息安全领域的核心议题。员工泄密可能致使企业核心数据、商业机密等关键资产的流失,进而给企业造成严重损失。为应对这一挑战,借助恰当的数据结构与算法成为强化信息防护的有效路径。本文专注于 C++ 语言中的布隆过滤器算法,深入探究其在防范员工泄密场景中的应用。
118 8
|
8月前
|
存储 监控 算法
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
在数字化办公时代,公司监控上网软件成为企业管理网络资源和保障信息安全的关键工具。本文深入剖析C++中的链表数据结构及其在该软件中的应用。链表通过节点存储网络访问记录,具备高效插入、删除操作及节省内存的优势,助力企业实时追踪员工上网行为,提升运营效率并降低安全风险。示例代码展示了如何用C++实现链表记录上网行为,并模拟发送至服务器。链表为公司监控上网软件提供了灵活高效的数据管理方式,但实际开发还需考虑安全性、隐私保护等多方面因素。
115 0
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
|
9月前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
262 3

热门文章

最新文章