(蓝桥杯C/C++)——动态规划(DP)

目录

一、线性DP

1.DP(动态规划)简介

2.动态规划的分析步骤

3.例题讲解

二、二维DP

1.二维DP简介

2.选数异或

三、最长上升子序列LIS

1.LIS简介

2.例题讲解

四、最长公共子序列LCS

1.最长公共子序列

2.最长公共子序列

2.求出具体子序列


一、线性DP

1.DP(动态规划)简介

DP(动态规划)全称DynamicProgramming,是运筹学的一个分支,是一种将复杂问题分解成很多重叠的子问题,并通过子问题的解得到整个问题的解的算法。

在动态规划中有一些概念:
状态:就是形如dp[il[il=val的取值,其中i,i为下标,也是用于描述、确定状态所需的变量,val为状态值。
状态转移:状态与状态之间的转移关系,一般可以表示为一个数学表达式,转移方向决迭代或递归方向。
最终状态:也就是题目所求的状态,最后的答案。

2.动态规划的分析步骤

1.确定状态,一般为“到第i个为止,xx为j(xx为k)的方案数/最小代价/最大价值”,可以根据数据范围和复杂度来推理。

2.确定状态转移方程,即从已知状态得到新状态的方法,并确保按照这个方向一定可以正确躾渥黨瘛得到最终状态。
根据状态转移的方向来决定使用迭代法还是递归法(记忆化)

3.确定最终状态并输出。

3.例题讲解

破损的楼梯
问题描述
小孟来到了一座高耸的楼梯前,楼梯共有N级台阶,从第0级台阶出发。小孟每次可以迈上1级或2级台阶,但是,楼梯上的a级、第02级、第 a1级,以此奔推。共 M 级台阶的台阶面已经坏了,不能上去。
现在,小孟想要到达楼梯的顶端,也就是第N级台阶,但他不能踩到坏了的台阶上。请问有多少种不踩到坏了的台阶上到达顶端的方案数?
由于方案数很大,请输出其对1e9+7取模的结果

例题分析

设状态dp[i]表示走到第i级台阶的方案数。
状态转移方程为dp[i]=dp[i-1]+dp[i-2],如
果i为破损的,则dp[il=0。

### 关于蓝桥杯 C/C++ A组的相关题解与资料 #### 蓝桥杯竞赛概述 蓝桥杯是一项面向全国大学生的编程比赛,其中C/C++分为多个组别,包括研究生组、大学A组、大学B组以及大学C组。这些组别的难度依次递减[^1]。 #### 大学A组的特点 对于C/C++大学A组而言,题目通常具有较高的复杂度和综合性,涉及算法设计、数据结构应用等多个方面。以下是针对一些典型问题的具体分析: --- #### 典型问题解析 ##### 问题1:兴趣小组成员统计 此问题是关于如何处理三个不同文件中的学生学号列表,并找出满足特定条件的学生数量。具体来说,目标是从给定的数据集中找到那些同时属于A组和B组但不属于C组的学生人数[^2]。 解决方法可以通过以下步骤实现(不使用自然语言描述顺序关系): - 使用哈希表或者集合来存储每组内的所有学号; - 对三组数据进行交集运算得到共同参与者; - 进一步排除掉也存在于第三组的情况;最后计算剩余元素的数量即可得出结果。 ```cpp #include <iostream> #include <unordered_set> #include <fstream> using namespace std; int main() { unordered_set<int> setA, setB, setC; ifstream fileA("A.txt"); int num; while (fileA >> num) { setA.insert(num); } fileA.close(); ifstream fileB("B.txt"); while (fileB >> num) { setB.insert(num); } fileB.close(); ifstream fileC("C.txt"); while (fileC >> num) { setC.insert(num); } fileC.close(); // 计算(A ∩ B) - C 的大小 int count = 0; for(auto &n : setA){ if(setB.find(n)!=setB.end() && setC.find(n)==setC.end()) ++count; } cout << count; } ``` 上述代码片段展示了通过读取文本文件并利用标准模板库(STL)容器完成所需操作的一种方式。 --- ##### 问题2:图论路径计数 另一个例子来源于第十二届比赛中的一道经典图论问题——基于节点间的互质关系构建连通图,并求解汉密尔顿回路总数[^3]。 这类问题往往需要借助深度优先搜索(DFS)动态规划(DP)技术来进行状态转移推导,在实际编码过程中还需要特别关注边界情况及性能优化措施。 ```cpp // 示例伪代码展示可能的解决方案框架 void dfs(int current_node, vector<bool>& visited, long& total_ways); bool is_coprime(int a, int b); long solve_hamiltonian_cycle(){ const int N=21; vector<vector<int>> adjacency_matrix(N+1,vector<int>(N+1)); // 初始化邻接矩阵... vector<bool> visited(N+1,false); long ways_count=0; dfs(1,visited,ways_count); return ways_count; } void dfs(int current_node, vector<bool>& visited, long& total_ways){ if(all nodes are visited and can go back to start node){ total_ways +=1 ; return; } foreach neighbor of current_node{ if(!visited[neighbor]){ mark as visited; call dfs recursively on this new state; unmark after recursion returns; } } } ``` 以上仅提供了一个简化版的概念模型用于说明思路。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只贴代码君

帅帅的你,留下你的支持吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值