算法 - 动态规划

文章目录

  • 介绍
  • 解题步骤
  • 题型
    • 背包问题
      • 01背包问题
        • 朴素算法(递归实现)
        • 备忘录算法(记忆化搜索)
        • 递推求解算法(动态规划)
    • 连续子段和问题
      • 最大连续子序列和
      • 最大连续子序列和的最优方案
    • 递推问题
      • 斐波那契数列II
      • 数塔II
      • 上楼II
    • 最长不下降子序列问题
      • 最长上升子序列

介绍

动态规划通常用于求解最优解问题,动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划求解的问题,经分解得到的子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题会被重复计算多次。而动态规划的做法是将已解决子问题的答案保存下来,在需要子问题答案的时候便可直接获得,而不需要重复计算,这样就可以避免大量的重复计算,提高效率。
在这里插入图片描述

解题步骤

  1. 确定dp数组(dp table)以及下标的含义
  2. 确定递推公式
  3. dp数组如何初始化
  4. 确定遍历顺序
  5. 举例推导dp数组
    在这里插入图片描述

题型

背包问题

01背包问题

有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。

第 i 件物品的体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式

第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。

接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。

输出格式

输出一个整数,表示最大价值。

数据范围

0<N,V≤1000

0<vi,wi≤1000

输入样例

4 5
1 2
2 4
3 4
4 5

输出样例:

8

朴素算法(递归实现)

这个问题是一个组合优化问题,其中目标是在不超过背包容量的前提下,从一组物品中选择一些物品,使得这些物品的总价值最大。

递归逻辑如下:

  1. 基本情况:如果背包容量C为0或物品数量n为0,返回0,因为没有物品可以放入背包或没有剩余空间。
  2. 如果最后一个物品的重量weights[n - 1]大于背包的剩余容量C,则不考虑这个物品,递归调用Recursive函数,减少物品数量n
  3. 否则,考虑两种情况:
    • 不选择最后一个物品,继续递归调用Recursive函数。
    • 选择最后一个物品,将其价值加到递归调用Recursive函数的结果上,但需要从背包容量中减去这个物品的重量。
// 递归算法
int Recursive(int C, int weights[], int values[], int n) {
    if (n == 0 || C == 0) {
        return 0;
    }
    if (weights[n - 1] > C) {
        return Recursive(C, weights, values, n - 1);
    }
    else {
        return max(Recursive(C, weights, values, n - 1),
            values[n - 1] + Recursive(C - weights[n - 1], weights, values, n - 1));
    }
}
备忘录算法(记忆化搜索)

备忘录技术(Memoization)的核心思想是存储已经计算过的结果,以避免在递归过程中对同一子问题的多次计算。当递归函数遇到一个之前已经计算过的子问题时,它可以直接从备忘录中获取结果,而不需要重新计算。这样做可以显著减少计算量,提高算法的效率。

memo[n][C] 代表在考虑前 n 个物品且背包容量为 C 时的最大价值。如果 memo[n][C] 已经被赋值(不是 -1),这意味着:

  1. 这个问题之前已经被计算过。
  2. 它的值是正确的,因为递归过程中会正确地计算并存储每个子问题的最大价值。

由于背包问题是一个优化问题,每次计算得到的 memo[n][C] 是在当前条件下能够得到的最大价值,这个值是最优解,不会因为再次计算而改变。因此,一旦 memo[n][C] 被计算并存储,它的值就是最终答案,不需要再次更新。

直接返回已经计算过的值有以下几个原因:

  • 避免重复计算:如果再次计算,会浪费计算资源,尤其是对于大型问题,这种重复计算会导致效率极低。
  • 保持最优性:每次递归调用都会找到在当前条件下的最大价值,因此存储的值是最优的,没有必要更新。
  • 确保正确性:递归算法保证了每个子问题只被计算一次,并且其结果被正确地存储和使用。

简而言之,备忘录中的值一旦被计算并存储,就代表了在给定子问题条件下的最优解,因此不需要再次计算或更新。这就是为什么在备忘录算法中,如果发现某个值已经被计算过,就直接返回该值,而不是重新计算或更新它。

备忘录逻辑如下:

  1. 基本情况:如果物品数量n为0或背包容量C为0,返回0。
  2. 查看备忘录:如果memo[n][C]已经被计算过(不是-1),则直接返回其值。
  3. 如果最后一个物品的重量weights[n - 1]大于背包的剩余容量C,则不考虑这个物品,递归调用Memoization函数。
  4. 否则,考虑两种情况:
    • 不选择最后一个物品,递归调用Memoization函数。
    • 选择最后一个物品,将其价值加到递归调用Memoization函数的结果上,但需要从背包容量中减去这个物品的重量。
  5. 将计算结果存储到备忘录memo[n][C]中,然后返回这个结果。
// 备忘录算法
int Memoization(int C, int weights[], int values[], int n, vector<vector<int>>& memo) {
    if (n == 0 || C == 0) {
        return 0;
    }
    if (memo[n][C] != -1) {
        return memo[n][C];
    }
    int result;
    if (weights[n - 1] > C) {
        result = Memoization(C, weights, values, n - 1, memo);
    }
    else {
        result = max(Memoization(C, weights, values, n - 1, memo),
                     values[n - 1] + Memoization(C - weights[n - 1], weights, values, n - 1, memo));
    }
    memo[n][C] = result; // 存储结果到备忘录
    return result;
}
递推求解算法(动态规划)

动态规划是一种通过将复杂问题分解成更简单的子问题来解决的方法,并且通过存储这些子问题的解来避免重复计算。

算法步骤如下:

  1. 内存分配:使用malloc为动态规划表V分配内存。V[i][j]表示考虑前i个物品且背包容量为j时的最大价值。

  2. 初始化边界条件

    • 如果背包容量为0,无论考虑多少物品,最大价值都是0,因此V[i][0] = 0
    • 如果没有物品,无论背包容量多大,最大价值也是0,因此V[0][j] = 0
  3. 动态规划计算

    • 外层循环i从1到n,表示考虑的物品数量。
    • 内层循环j从1到C,表示背包容量。
    • 如果当前物品的重量大于背包容量,则不能放入背包,当前状态的最大价值等于不包含当前物品时的最大价值,即V[i - 1][j]
    • 否则,考虑两种情况:不放入当前物品或放入当前物品。选择两者中价值更大的一个作为当前状态的最大价值。
  4. 返回最大价值:计算完成后,V[n][C]存储了最终的最大价值。

  5. 内存释放:使用free释放之前分配的内存。

// 动态规划算法
int Dynamic(int C, int weights[], int values[], int n) {
   int** V = (int**)malloc((n + 1) * sizeof(int*));
    for (int i = 0; i <= n; i++) {
        V[i] = (int*)malloc((C + 1) * sizeof(int));
    }
    // 初始化边界条件
    for (int i = 0; i <= n; i++) {
        V[i][0] = 0;
    }
    for (int j = 0; j <= C; j++) {
        V[0][j] = 0;
    }
    // 动态规划计算最大价值
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= C; j++) {
            if (weights[i - 1] > j) {
                V[i][j] = V[i - 1][j];
            } else {
                V[i][j] = max(V[i - 1][j], values[i - 1] + V[i - 1][j - weights[i - 1]]);
            }
        }
    }
    int max_value = V[n][C];
    // 释放动态分配的内存
    for (int i = 0; i <= n; i++) {
        free(V[i]);
    }
    free(V);
    return max_value;
}

连续子段和问题

最大连续子序列和

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6;
int dp[N] = {0},a[N],n;

int main(){
	cin >> n;
	for(int i=1;i<=n;i++) cin >> a[i];
	for(int i=1;i<=n;i++){
		dp[i] = max(dp[i-1]+a[i],a[i]);
	}
	cout << *max_element(dp+1,dp+n+1);
	return 0;
}

最大连续子序列和的最优方案

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6;
int dp[N] = {0},start[N],a[N],n,terminal,maxRes = INT32_MIN;

int main(){
	cin >> n;
	for(int i=1;i<=n;i++) cin >> a[i];
	a[0] = 1;
	for(int i=1;i<=n;i++){
		if((a[i]+dp[i-1]) >= a[i]){
			dp[i] = a[i]+dp[i-1];
			start[i] = start[i-1];
		}else{
			dp[i] = a[i];
			start[i] = i;
		}
	}
	for(int i=1;i<=n;i++){
		if(dp[i] > maxRes){
			terminal = i;
			maxRes = dp[i];
		}
	}
	cout << maxRes << " " << start[terminal] << " " << terminal;
	return 0;
}

递推问题

斐波那契数列II

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
int dp[10002];

int main(){
    dp[1] = 1;
    dp[2] = 1;
    int n;
    cin >> n;
    for(int i = 3;i <= n;i ++){
        dp[i] = (dp[i-1] + dp[i-2]);
    }
    cout << dp[n]%10007;
}

数塔II

在这里插入图片描述
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
int dp[101][101],a[101][101];

int main(){
	int n;
	cin >> n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++){
			cin >> a[i][j];
		}
	}
	for(int i=1;i<=n;i++){
		dp[n][i] = a[n][i];
	}
	for(int i=n-1;i>0;i--){
		for(int j=1;j<=i;j++){
			dp[i][j] = max(dp[i+1][j],dp[i+1][j+1]) + a[i][j];
		}
	}
	cout << dp[1][1];
}

上楼II

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
int dp[100001],n;

int main(){
	dp[1] = 1;
	dp[2] = 2;
	cin >> n;
	for(int i=3;i<=n;i++){
		dp[i] = (dp[i-1] + dp[i-2])%10007;
	}
	cout << dp[n];
}

最长不下降子序列问题

最长上升子序列

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5;
int a[N],n,dp[N];

int main(){
	cin >> n;
	for(int i = 0;i < n;i ++) cin >> a[i];
	for(int i = 0;i < n;i ++){ 
		dp[i] = 1;
		for(int j=0;j<i;j++){
			if(a[j]<=a[i] && dp[j] + 1 > dp[i]){
				dp[i] = dp[j] + 1;
			}
		}
	}
	cout << *max_element(dp,dp+n);
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/783481.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

选项卡切换(排他法、轮转法、轮转法之事件委托)

选项卡需求&#xff1a; tabbar content 两部分的内容一一对应&#xff0c;我们点击某一个tab的时候&#xff0c;该tab的类名设置为on&#xff0c;其他的tab要清除on类名&#xff0c;对应的content的类名要设置为 active &#xff0c;其他的content清除active类名。 <!DOCTY…

vue通过后台返回的数字显示不同的文字内容,多个内容用、隔开

后台返回的数据 显示效果&#xff1a; html&#xff1a; <el-table-columnalign"center"label"使用过的小程序"width"124"v-if"activeTab 0"><template #default"scope"><divv-for"(item, index) in s…

众所周知沃尔玛1P是怎么运营?

​​沃尔玛的1P模式&#xff0c;即第一方供应商模式&#xff0c;是其独特的采购策略。在这种模式下&#xff0c;供应商先将商品卖给沃尔玛&#xff0c;由沃尔玛负责库存管理和销售。沃尔玛通过强大的采购和物流能力控制库存&#xff0c;确保商品品质&#xff0c;为客户提供更加…

【操作系统】进程管理——调度算法(个人笔记)

学习日期&#xff1a;2024.7.4 内容摘要&#xff1a;各种调度算法的思想、规则、优缺点介绍 为什么要有调度算法&#xff1f; 调度算法就好比一群人在银行办理业务&#xff0c;准备办理业务的人就是进程/作业&#xff0c;银行窗口的工作人员就是CPU&#xff0c;进程往往是比C…

旅游计划定制小程序网页模板源码

手机在线旅游定制服务&#xff0c;定制旅游出行app小程序模板。包含&#xff1a;定制介绍、定制表单填写、我的订单等。 旅游计划定制小程序网页模板源码

力扣爆刷第161天之TOP100五连刷71-75(搜索二叉树、二维矩阵、路径总和)

力扣爆刷第161天之TOP100五连刷71-75&#xff08;搜索二叉树、二维矩阵、路径总和&#xff09; 文章目录 力扣爆刷第161天之TOP100五连刷71-75&#xff08;搜索二叉树、二维矩阵、路径总和&#xff09;一、98. 验证二叉搜索树二、394. 字符串解码三、34. 在排序数组中查找元素的…

idea Git操作

1、代码拉取&#xff08;左上角&#xff09; 或 2、代码push&#xff08;左上角&#xff09; 3、切换分支&#xff08;右下角&#xff09; 4、分支管理 5、当前分支和某一个分支对比差异 6、当前分支某一个提交需要恢复成提交前状态&#xff08;revert&#xff09; 7、其他分…

信息技术课上的纪律秘诀:营造有序学习环境

信息技术课是学生们探索数字世界的乐园&#xff0c;但同时也是课堂纪律管理的挑战场。电脑、网络、游戏等元素可能分散学生的注意力&#xff0c;影响学习效果。本文将分享一些有效的策略&#xff0c;帮助教师在信息技术课上维持课堂纪律&#xff0c;确保教学活动顺利进行。 制…

简过网:快来看看你的专业能考哪个类型的事业单位?

你的专业能考哪个类型的事业单位&#xff0c;你知道吗&#xff1f;想考事业单位的姐妹&#xff0c;一定要在备考之前&#xff0c;查清楚你的专业适不适合考事业单位、考哪类事业编以及能报考哪些岗位&#xff1f;这个才能上岸的几率更高一些&#xff01; 事业单位有5类岗位&am…

安全防御(防火墙)

第二天&#xff1a; 1.恶意程序---一般会具有一下多个或则全部特点 1.非法性&#xff1a;你未经授权它自动运行或者自动下载的&#xff0c;这都属于非法的。那恶意程序一般它会具有这种特点&#xff0c; 2.隐蔽性&#xff1a;一般隐藏的会比较深&#xff0c;目的就是为了防止…

学生护眼台灯哪个牌子实用?值得入手的学生护眼台灯十大排名分析

在这个数码时代&#xff0c;人们对屏幕的依赖程度越来越高&#xff0c;尤其是孩子们。他们不仅在学校里需要长时间盯着教科书&#xff0c;还会在学习和娱乐中使用各种数码设备。然而&#xff0c;这也使得眼睛健康问题逐渐凸显&#xff0c;尤其是儿童近视的问题。为了保护视力&a…

重庆交通大学数学与统计学院携手泰迪智能科技共建的“智能工作室”

2024年7月4日&#xff0c;重庆交通大学数学与统计学院与广东泰迪智能科技股份有限公司携手共建的“智能工作室”授牌仪式在南岸校区阳光会议室举行。此举标志着数统学院与广东泰迪公司校企合作新篇章的开启&#xff0c;也预示着学院在智能科技教育领域的深入探索和实践。 广东…

利用Python进行数据分析PDF下载经典数据分享推荐

本书由Python pandas项目创始人Wes McKinney亲笔撰写&#xff0c;详细介绍利用Python进行操作、处理、清洗和规整数据等方面的具体细节和基本要点。第2版针对Python 3.6进行全面修订和更新&#xff0c;涵盖新版的pandas、NumPy、IPython和Jupyter&#xff0c;并增加大量实际案例…

SSM高校学生综合测评系统-计算机毕业设计源码16154

摘要 随着互联网时代的到来,同时计算机网络技术高速发展,网络管理运用也变得越来越广泛。因此,建立一个BS 结构的高校学生综合测评系统,会使高校学生综合测评系统工作系统化、规范化,也会提高高校学生综合测评系统平台形象,提高管理效率。 本学生综合测评系统是针对目前高校学生…

C++第二弹 -- C++基础语法下(引用 内联函数 auto关键字 范围for 指针空值)

本篇大纲 前言一. 引用续讲1. 传值,传引用效率对比2. 类型转换和表达式传引用的注意事项3. 引用与指针 二. 内联函数1. 概念2. 特性3. 面试题 三. auto关键字(C11)1. 类型别名思考2. auto简介3. auto的使用细则4. auto不能推导的场景 四. 基于范围的for循环(C11)1. 范围for的语…

运维系列.Nginx:自定义错误页面

运维系列 Nginx&#xff1a;自定义错误页面 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/…

医院人员管理项目01_下午,css

文章目录 层叠样式表在html文件中引入css样式表&#xff1a;2种方法如何设置样式&#xff1a;3种css选择器继承权重 层叠样式表 引入html网页中的方式&#xff0c;共3种。 行内样式&#xff08;内联样式&#xff09;&#xff1a;直接在html中设置 内部样式&#xff1a;css代…

latex改写字体和字号

文章目录 字体使用宏包设置命令声明命令 字号例子设置特定字号 设置行间距用\setlength{\baselineskip}{24pt}设置\renewcommand{\baselinestretch}{2} \selectfont中文行距&#xff08;{ctex}&#xff09; 补充&#xff1a; 字体 使用宏包 \usepackage{ctex}设置命令 只对确…

【包邮送书】AIGC时代程序员的跃迁——编程高手的密码武器

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术。关…

20240708 Transformer

如何从浅入深理解transformer&#xff1f; - 知乎 1.出现了一些基于自监督的方法&#xff0c;这包括基于对比学习的方法如MoCo和SimCLR&#xff0c;和基于图像掩码的方法如MAE和BeiT 2、Transformer结构及其应用详解--GPT、BERT、MT-DNN、GPT-2 - 知乎 3. "Decoder-o…