当前位置: 首页 > news >正文

杭电oj(1087、1203、1003)题解

 

 

DP 即动态规划(Dynamic Programming),是一种通过把原问题分解为相对简单的子问题,并保存子问题的解来避免重复计算,从而解决复杂问题的算法策略。以下从几个方面简述动态规划:

基本思想

动态规划的核心在于 “分治” 和 “最优子结构”。它将一个复杂问题分解为一系列相互关联的子问题,通过求解子问题并保存其解,避免对相同子问题的重复求解,从而减少计算量。同时,原问题的最优解可以由子问题的最优解组合而成,这就是最优子结构性质。

适用条件

  • 最优子结构性质:问题的最优解包含其子问题的最优解。即可以通过子问题的最优解推导出原问题的最优解。例如,在背包问题中,对于一个容量为 W 的背包和 n 个物品,要得到其最优装法,可以先考虑容量为 W - w[i]w[i] 为第 i 个物品的重量)的背包和前 n - 1 个物品的最优装法。
  • 子问题重叠性质:在求解过程中,会多次遇到相同的子问题。动态规划通过保存子问题的解,避免了对这些子问题的重复计算,从而提高了效率。比如在斐波那契数列的计算中,直接递归计算会有大量重复的子问题计算,而使用动态规划可以避免这种情况。

求解步骤

  1. 定义状态:明确问题的状态表示,即如何用一个或多个变量来描述子问题。例如,在最长上升子序列问题中,可以定义状态 dp[i] 表示以第 i 个元素结尾的最长上升子序列的长度。
  2. 确定状态转移方程:根据问题的最优子结构性质,找出状态之间的转移关系。状态转移方程描述了如何从子问题的解推导出原问题的解。例如,在最长上升子序列问题中,状态转移方程为 dp[i] = max(dp[j] + 1) (0 <= j < i 且 a[j] < a[i])
  3. 初始化:确定初始状态的值,这些初始状态是问题的边界条件。例如,在斐波那契数列的动态规划求解中,dp[0] = 0dp[1] = 1 就是初始状态。
  4. 计算顺序:根据状态转移方程,确定计算状态的顺序,一般是从简单的子问题开始,逐步求解更复杂的问题。

应用场景

动态规划在很多领域都有广泛的应用,常见的问题包括:

  • 背包问题:如 0 - 1 背包问题、完全背包问题等,用于在一定的约束条件下选择物品,使得总价值最大。
  • 最长公共子序列问题:找出两个序列中最长的公共子序列,在生物信息学、版本控制等领域有应用。
  • 最短路径问题:如 Floyd - Warshall 算法,用于求解图中任意两点之间的最短路径。
  • 资源分配问题:在多个项目或任务之间分配资源,以达到最优的效益。

目录

1087

题目

思路

代码详细步骤

动态规划初始化

状态转移

找出最大值

代码

1203

题目

思路

代码

1003

题目

思路

代码


1087

题目

思路

动态规划算法的核心在于将原问题分解为一系列子问题,并通过求解子问题来得到原问题的解。在这个问题中,我们定义状态 dp[i] 表示以第 i 个元素结尾的最长上升子序列的最大和。通过遍历序列中的每个元素,我们可以根据之前的状态来更新当前状态,最终找出所有状态中的最大值,即为最长上升子序列的最大和。

代码详细步骤

动态规划初始化
  • dp[0]=a[0];:将 dp[0] 初始化为 a[0],因为以第一个元素结尾的最长上升子序列就是它本身,其和就是 a[0]
状态转移
  • 外层循环 for(int i = 1; i < n; i++):遍历数组中的每个元素,从第二个元素开始。
  • dp[i]=a[i];:将 dp[i] 初始化为 a[i],表示以第 i 个元素结尾的最长上升子序列至少包含该元素本身。
  • 内层循环 for(int j = 0; j < i; j++):遍历当前元素 a[i] 之前的所有元素。
  • if(a[i]>a[j]):判断 a[i] 是否大于 a[j],如果满足条件,说明可以将 a[i] 接到以 a[j] 结尾的最长上升子序列后面。
  • dp[i]=max(a[i]+dp[j],dp[i]);:更新 dp[i] 的值,取 a[i] + dp[j] 和 dp[i] 中的最大值。a[i] + dp[j] 表示将 a[i] 接到以 a[j] 结尾的最长上升子序列后面得到的新子序列的和。
找出最大值
  • int maxnum=-1e9;:将 maxnum 初始化为一个较小的值 -1e9,确保后续找到的任何 dp[i] 值都能更新 maxnum
  • for(int i = 0; i < n; i++){ maxnum=max(maxnum,dp[i]); }:遍历 dp 数组,找出其中的最大值。

代码

#include<iostream>
#include<algorithm>
using namespace std;
int dp[1010],a[1010],n; 
int main(){while(cin>>n&&n){for(int i=0;i<n;i++){cin>>a[i];}dp[0]=a[0];for(int i=1;i<n;i++){dp[i]=a[i];for(int j=0;j<i;j++){if(a[i]>a[j]){dp[i]=max(a[i]+dp[j],dp[i]);}}}int maxnum=-1e9;for(int i=0;i<n;i++){maxnum=max(maxnum,dp[i]);}cout<<maxnum<<endl;}return 0;
}

1203

题目

思路

外层循环 for(int i = 0; i < m; i++):遍历每一个物品。

内层循环 for(int j = n; j >= a[i]; j--):从背包的总容量 n 开始,倒序遍历到当前物品的重量 a[i]。倒序遍历是为了保证每个物品只被选择一次,这是 0 - 1 背包问题的常见处理方式。

状态转移方程 dp[j]=max(dp[j],dp[j-a[i]]+prob[i]-dp[j-a[i]]*prob[i]);

dp[j] 表示不选择当前物品 i 时,背包容量为 j 的最大成功概率。

dp[j - a[i]] 表示在不放入当前物品 i 时,背包容量为 j - a[i] 的最大成功概率。

dp[j - a[i]] + prob[i] - dp[j - a[i]] * prob[i] 表示选择当前物品 i 时的成功概率。这里基于概率的计算原理,假设物品的成功是相互独立事件,使用公式 P(A 或 B) = P(A) + P(B) - P(A) * P(B) 来计算选择当前物品后的成功概率。

通过 max 函数取两者中的最大值更新 dp[j]

代码

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
double dp[N];
double prob[N];
int a[N];
int n,m;
int main(){while(cin>>n>>m){if(n==0 && m==0) break;for(int i=0;i<m;i++){cin>>a[i]>>prob[i];}memset(dp,0,sizeof(dp));for(int i=0;i<m;i++){for(int j=n;j>=a[i];j--){dp[j]=max(dp[j],dp[j-a[i]]+prob[i]-dp[j-a[i]]*prob[i]);}}printf("%.1lf%%\n",dp[n]*100);}return 0;
}

1003

题目

思路

状态转移方程 dp[j]=max(dp[j],dp[j-a[i]]+prob[i]-dp[j-a[i]]*prob[i]);

dp[j] 表示不选择当前物品 i 时,背包容量为 j 的最大成功概率。

dp[j - a[i]] 表示在不放入当前物品 i 时,背包容量为 j - a[i] 的最大成功概率。

dp[j - a[i]] + prob[i] - dp[j - a[i]] * prob[i] 表示选择当前物品 i 时的成功概率。这里基于概率的计算原理,假设物品的成功是相互独立事件,使用公式 P(A 或 B) = P(A) + P(B) - P(A) * P(B) 来计算选择当前物品后的成功概率。

通过 max 函数取两者中的最大值更新 dp[j]

代码

#include<iostream>
using namespace std;
int n,m,l,r,maxnum,sum,temp,num;
int main(){cin>>n;for(int i=0;i<n;i++){l=0,r=0,temp=1,maxnum=-20000,sum=0;cin>>m;for(int j=1;j<=m;j++){cin>>num;sum+=num;if(sum>maxnum){r=j;maxnum=sum;l=temp;}if(sum<0){temp=j+1;sum=0;}}cout<<"Case "<<(i+1)<<":"<<endl<<maxnum<<" "<<l<<" "<<r<<endl;if(i<n-1) cout<<endl;}return 0;
}

相关文章:

  • 什么是CAN的非破坏仲裁?
  • Java基础(包装器,关键字,修饰符,Object)
  • 实验2 python的TCP群聊系统实现
  • Java基础:认识注解,模拟junit框架
  • 3dmax模型怎么导入酷家乐插件,材质贴图在,可优化不卡,可批量处理,无需打开一个个max,可批量转FBX/GLB/GLTF/OBJ/SU
  • 查询Hologres或postgresql中的数据
  • 即插即用模块(3) -LSK 特征提取
  • Spring--统一数据返回格式与统一异常处理
  • 将 MySQL 8 主从复制延迟优化到极致
  • 如何在iStoreOS DHCP中排除特定IP地址
  • zkPass案例实战之合约篇
  • 【论文#目标检测】Attention Is All You Need
  • 【泊松过程和指数分布】
  • 力扣DAY63-67 | 热100 | 二分:搜索插入位置、搜索二维矩阵、排序数组查找元素、搜索旋转排序数组、搜索最小值
  • OpenCV 图形API(52)颜色空间转换-----将 NV12 格式的图像数据转换为 RGB 格式的图像
  • 计算机视觉基础
  • 提高Spring Boot开发效率的实践
  • MsQuick编译和使用
  • c++概念——模板的进阶讲解
  • django软件开发招聘数据分析与可视化系统设计与实现(源码+lw+部署文档+讲解),源码可白嫖!
  • 这场宣介会,重庆市委书记和中联部部长同台为外宾答疑解惑
  • 朱守科已任西藏自治区政府党组成员、自治区公安厅党委书记
  • 神二十6个半小时到站
  • 新闻1+1丨“龟速”行驶要治理,还要治什么?
  • 国产手术机器人+5G技术,上海医生同一天远程为五地患者开刀
  • 消费维权周报丨上周合同纠纷类投诉多,合同未到期关闭门店等