算法设计与分析复习--动态规划

news2024/11/15 21:46:33

文章目录

  • 上一篇
  • 动态规划性质
  • 矩阵连乘问题
  • 凸多边形最优三角部分
  • 最长公共子序列
  • 0-1背包问题
  • 下一篇

上一篇

算法设计与分析复习–递归与分治(二)

动态规划性质

与分析法类似:将原问题分解为子问题
不同点:不是通过递归的方式,而是自底向上的求解问题
在这里插入图片描述

矩阵连乘问题

在这里插入图片描述
矩阵连乘的次数是左矩阵行列,右矩阵行列取出左右中进行相乘。
在这里插入图片描述
由于矩阵乘积需要满足左矩阵列等于右矩阵的行,所以可以用一维数组进行存n个矩阵,共n + 1个元素,从第一个矩阵的(1)行(2)列,第二个矩阵由于行与第一个的列相同就不在重复存储所以只需存第二个的(3)列,一次类推

数据结构:
a[N] 存矩阵行列
dp[N][N] => dp[i][j]表示第i个矩阵到第j个矩阵的最小连乘次数

因为是从小到大算每个区间内的最小值=> 区间dp

在这里插入图片描述

#include <iostream>
#include <cstring>
#include <algorithm>
#include <climits>

using namespace std;

const int N = 110;

int a[N], dp[N][N], n;

void out()
{
    for (int i = 1; i <= n; i ++)
    {
        for (int j = 1; j <= n; j ++)
            printf("%d ", dp[i][j]);
        puts("");
    }
}

int main()
{
    scanf("%d", &n);
    
    for (int i = 0; i <= n; i++) scanf("%d", &a[i]);

    // 初始化dp数组
    memset(dp, 0, sizeof(dp));

    for(int len = 2; len <= n; len ++)
    {
        for (int i = 1; i + len - 1 <= n; i ++)
        {
            int j = i + len - 1;
            dp[i][j] = 1e8; // 初始化为一个较大的值

            for (int k = i; k < j; k ++)
            {
                dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + a[i - 1] * a[k] * a[j]);
                // out();
            }
        }
    }
    out();
    printf("%d\n", dp[1][n]);
    return 0;
}

在这里插入图片描述

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

区间DP类似题目 AcWing.282石子合并

在这里插入图片描述

凸多边形最优三角部分

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

在这里插入图片描述
可以转换成矩阵连乘问题
在这里插入图片描述
加完括号的形式就是那个最优三角形的位置

数据结构
v[N]: 表示每个结点对应值
dp[N][N]: dp[i][j]表示结点从 i 到 j 的三角的权重,取min
状态计算(区间dp):
d p [ i ] [ j ] = m i n { d p [ i ] [ k ] + d p [ k + 1 ] + w ( v i − 1 v k v j ) } dp[i][j] = min\{ dp[i][k] + dp[k + 1] + w(v_{i-1}v_kv_j)\} dp[i][j]=min{dp[i][k]+dp[k+1]+w(vi1vkvj)}

在这里插入图片描述

最长公共子序列

在这里插入图片描述

AcWing897.最长公共子序列

在这里插入图片描述

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

const int N = 1010;

char a[N], b[N];
int dp[N][N], n, m;
int x[N][N];//寻路数组
vector<char> ans;

void out()
{
    for (int i = 1; i <= n; i ++)
    {
        for (int j = 1; j <= m; j ++)
            cout << dp[i][j] << ' ';
        cout << endl;
    }
    cout << "*****************" << endl;
    for (int i = 1; i <= n; i ++)
    {
        for (int j = 1; j <= m; j ++)
            cout << x[i][j] << ' ';
        cout << endl;
    }
    cout << "*****************" << endl;
}

void trackback(int i, int j)
{
    if (i <= 0 || j <= 0) return;
    if (x[i][j] == 1){
        ans.push_back(a[i]);
        trackback(i - 1, j - 1);
    } 
    else if (x[i][j] == 2) trackback(i - 1, j);
    else trackback(i, j - 1);
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    
    cin >> n >> m;
    cin >> a + 1 >> b + 1;//因为有i - 1操作所以起始下标要从1开始防止数组越界
    
    for(int i = 1; i <= n; i ++)
    {
        for (int j = 1; j <= m; j ++)
        {
            if(a[i] == b[j]) {
                dp[i][j] = dp[i - 1][j - 1] + 1;
                x[i][j] = 1;// 1表示i和j都要选为对应公共元素
            }
            else if(dp[i - 1][j] >= dp[i][j - 1]){
                dp[i][j] = dp[i - 1][j];
                x[i][j] = 2;//回溯沿着表上走
            }
            else{
                dp[i][j] = dp[i][j - 1];
                x[i][j] = 3;//沿着表左走
            }
        }
    }
    out();
    cout << dp[n][m] << endl;
    trackback(n, m);
    reverse(ans.begin(), ans.end());//答案顺序反了,需要翻转一下
    for (auto i : ans)
        cout << i;
    return 0;
}

在这里插入图片描述
在这里插入图片描述
输入顺序写反了,列是第一个序列,行时第二个序列
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

0-1背包问题

在这里插入图片描述

AcWing2. 01背包

在这里插入图片描述

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010;

int dp[N][N], w[N], v[N], n, c;

int main()
{
    scanf("%d%d", &n, &c);
    
    for (int i = 1; i <= n; i ++) scanf("%d%d", &w[i], &v[i]);
    
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= c; j ++)
        {
            dp[i][j] = dp[i - 1][j];
            if(w[i] <= j) dp[i][j] = max(dp[i][j], dp[i - 1][j - w[i]] + v[i]);
        }
    
    printf("%d", dp[n][c]);
    return 0;
}

观察发现状态计算的方程中只用到了第i行和第i - 1行,所以可以用滚动数组,将这个二维数组优化成一维数组
在这里插入图片描述

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010;

int dp[N], w[N], v[N], n, c;

int main()
{
    scanf("%d%d", &n, &c);
    
    for (int i = 1; i <= n; i ++) scanf("%d%d", &w[i], &v[i]);
    
    for (int i = 1; i <= n; i ++)
        for (int j = c; j >= 1; j --)// 也可以将下面if条件拿到上面=> for(int j = c; j >= w[i]; j --)
        {
            if(w[i] <= j) dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
        }
    
    printf("%d", dp[c]);
    return 0;
}

带结果回溯的写法
如果用回滚数组就找不到对应物品的坐标了,但是可以找到对应价值的物品

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010;

int dp[N][N], w[N], v[N], n, c;
int x[N][N];

void out()
{
    for (int i = 1; i <= n; i ++)
    {
        for (int j = 1; j <= c; j ++)
            printf("%d ", dp[i][j]);
        puts("");
    }
    puts("************");
    for (int i = 1; i <= n; i ++)
    {
        for (int j = 1; j <= c; j ++)
            printf("%d ", x[i][j]);
        puts("");
    }
    puts("************");
}

void trackback(int i, int j, int f)
{
    if(i <= 0 || j <= 0) return;
    if(f == 0){
        printf("不选第%d件商品\n", i);
        trackback(i - 1, j, x[i - 1][j]);
    }
    if(f == 1){
        printf("选第%d件商品\n", i);
        trackback(i - 1, j - w[i], x[i - 1][j - w[i]]);//选这件商品后的坐标需要算一下
    }
}

int main()
{
    scanf("%d%d", &n, &c);
    
    for (int i = 1; i <= n; i ++) scanf("%d", &w[i]);
    for (int i = 1; i <= n; i ++) scanf("%d", &v[i]);
    
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= c; j ++){
            if(w[i] <= j && dp[i - 1][j] < dp[i - 1][j - w[i]] + v[i]){
                dp[i][j] = dp[i - 1][j - w[i]] + v[i];
                x[i][j] = 1;
            }
            else{
                dp[i][j] = dp[i - 1][j];
                x[i][j] = 0;
            }
        }
    out();
    printf("%d\n", dp[n][c]);
    trackback(n, c, x[n][c]);
    return 0;
}

在这里插入图片描述

在这里插入图片描述

下一篇

算法设计与分析复习–贪心(一)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

pytest测试框架介绍(1)

又来每天进步一点点啦~~~ 一、Pytest介绍&#xff1a; pytest 是一个非常成熟的全功能的Python测试框架&#xff1b; pytest 简单、灵活、易上手&#xff1b; 支持参数化 能够支持简单的单元测试和复杂的功能测试&#xff0c;可以做接口自动化测试&#xff08;pytestrequests&…

【Qt开发流程之】窗口部件

qt类关系图 创建Qt项目时&#xff0c;发现提供的窗体默认 基类有&#xff1a;QMainWindow、QDialog、QWidget这三种。 之后&#xff0c;你会发现&#xff0c;这3中窗体在UI交互中&#xff0c;用的也是最多的。 以下是Qt类关系图&#xff1a; 基础窗口控件QWidget 由上图可以…

分享禁止Win10更新的两种方法

深恶痛绝 Windows更新简直就是毒瘤&#xff0c;总是在某些不需要的时候提示更新&#xff0c;而且关闭服务后总有办法重启。老是关不掉。 如果每次都是正常更新&#xff0c;好像也没啥所谓&#xff0c;但是总有那么一两次会蓝屏、黑屏、开不了机…… 52出品 下面是吾爱社区找…

设计模式(二)-创建者模式(2-0)-简单工厂模式

一、简单工厂模式定义 客户端不需要关注创建实例的过程。于是需要通过工厂模式&#xff0c;要把创建对象过程和使用对象进行分离。所以客户端只要使用对象即可&#xff0c;而创建对象过程由一种类来负责&#xff0c;该类称为工厂类。 由于创建实例的方式是在静态方法里实现的…

数睿通2.0数据接入、数据开发、系统权限、集群监控全面升级

引言 数睿通 2.0 数据中台迎来了11月份的更新&#xff0c;感谢大家的支持&#xff0c;本次更新主要包括以下内容&#xff1a; 数据库支持 MongoDB数据接入支持 MongoDB&#xff0c;支持自定义 SQL 采集&#xff0c;支持停止运行中的任务数据生产支持 FlinkJar 任务&#xff0…

线性变换功能块S_RTI工程上的主要应用

西门子S_RTI模拟量转换功能块算法公式和代码介绍请参考下面文章链接: PLC模拟量输出 模拟量转换FC S_RTI-CSDN博客文章浏览阅读5.3k次,点赞2次,收藏11次。1、本文主要展示西门子博途模拟量输出转换的几种方法, 方法1:先展示下自编FC:计算公式如下:intput intput Real IS…

OS 进程同步

基本概念 定义&#xff1a;把异步环境下的一组并发进程因直接制约而相互发送消息、相互合作、相互等待&#xff0c;使得各进程按一定的速度执行的过程&#xff0c;称为进程同步 协作进程&#xff1a;具有同步关系的一组并发进程 进程同步机制的主要任务&#xff1a;在执行次…

Linux调试器:gdb的使用

我们知道在Visual Studio2022中&#xff0c;我们可以对编好的代码进行调试来分析dug的位置&#xff0c;那Linux环境下如何进行程序的调试呢&#xff1f;那就是使用Linux调试器&#xff1a;gdb。 目录 1.背景 2. 开始使用 1.背景 程序的发布方式有两种&#xff0c;debug模式…

mysql的行列互转

mysql的行列互转 多行转多列思路实现代码 多列转多行思路代码 多行转多列 多行转多列&#xff0c;就是数据库中存在的多条具有一定相同值的行数据&#xff0c;通过提取相同值在列头展示来实现行数据转为列数据&#xff0c;一般提取的值为枚举值。 思路 转换前表样式 -> 转…

从 0 开始手写一个 Mybatis 框架,三步搞定!

MyBatis框架的核心功能其实不难&#xff0c;无非就是动态代理和jdbc的操作&#xff0c;难的是写出来可扩展&#xff0c;高内聚&#xff0c;低耦合的规范的代码。本文完成的Mybatis功能比较简单&#xff0c;代码还有许多需要改进的地方&#xff0c;大家可以结合Mybatis源码去动手…

打开游戏提示xapofx1_5.dll丢失如何修复?xapofx1_5.dll缺失的修复教程分享

xapofx1_5.dll是一个重要的Windows系统文件&#xff0c;它主要负责处理图形渲染和多媒体功能。如果在计算机中找不到xapofx1_5.dll&#xff0c;可能会导致程序无法正常运行。下面是关于xapofx1_5.dll丢失的4个修复方法以及xapofx1_5.dll的作用和丢失原因的介绍。 一、xapofx1_…

MySQL 教程 1.2

上期教程网友笔记整理 MySQL 重置密码 如果你忘记 MySQL 密码&#xff0c;可以通过修改 my.cnf 文件添加 skip-grant-tables 来重置密码&#xff0c;步骤如下&#xff1a; 1、打开 my.cnf 配置文件&#xff0c;找到 [mysqld] &#xff0c;然后在该行下面添加以下参数&#x…

基于STM32CubeMX和keil采用RTC时钟周期唤醒和闹钟实现LED与BEEP周期开关

文章目录 前言1. RTC概念1.1 RTC的时钟信号源1.2 预分频器1.3 实时时钟与日历数据1.4 周期性自动唤醒1.5 可编程闹钟 2. RTC相关中断3. STM32CubeMX配置3.1 时钟配置3.2 引脚配置3.3 RTC配置3.3.1 模式选择3.3.2 RTC基本参数配置3.3 中断配置 4. 代码编写总结 前言 RTC的功能有…

数据结构与算法之美学习笔记:22 | 哈希算法(下):哈希算法在分布式系统中有哪些应用?

目录 前言应用五&#xff1a;负载均衡应用六&#xff1a;数据分片应用七&#xff1a;分布式存储解答开篇 & 内容小结 前言 本节课程思维导图 今天&#xff0c;我们再来看剩余三种应用&#xff1a;负载均衡、数据分片、分布式存储。你可能已经发现&#xff0c;这三个应用都…

volatile 无法保证原子性 案例展示

volatile 无法保证原子性 在 Java 中&#xff0c;原子性是指一个操作是不可中断的&#xff0c;要么都执行要么都不执行。 但是 volatile 修饰的变量&#xff0c;只是保证了从主内存加载到工作内存的值是最新的&#xff0c;并不能保证对变量的操作是原子性的 变量的写操作和读…

在线生成含logo的彩色二维码工具

具体请前往&#xff1a;在线二维码生成工具--可生成指定大小和颜色的彩色二维码图片,并支持Logo

arcgis属性表十进制度转换成度分秒格式--转换坐标注记法

1、有一组点数据&#xff0c;如下&#xff1a; 2、为其添加XY坐标&#xff0c;如下&#xff1a; 打开属性表&#xff0c;可得到对应点的XY的十进制度坐标&#xff0c;如下&#xff1a; 3、将十进制度转换成度分秒格式&#xff0c;如下&#xff0c;使用转换坐标注记法工具&#…

支付、结算、对账流程

1、支付过程概览 2、微信支付流程 以微信支付为例,用户使用北京银行,商户收款银行为工行银行,列出机构名 用户在商户处选购商品或服务,选择使用微信支付进行付款。用户打开微信支付,输入支付密码或进行指纹识别等身份验证。微信支付系统将支付请求发送给北京银行。北京银行…

Java Web 实战 20 - HTTP PK HTTPS ? HTTPS 大获全胜 ?

HTTP VS HTTPS 一 . HTTPS1.1 臭名昭著的运营商劫持1.2 加密是什么 ?1.3 HTTPS 的加密过程对称加密非对称加密引入 "证书" 机制 1.4 HTTP VS HTTPS Hello , 大家好 , 好久没有更新 JavaWeb 模块的内容了 . 博主这篇文章主要给大家讲解一下 HTTPS 以及与 HTTP 的区别…

“新KG”视点 | 知识图谱与大语言模型协同模式探究

OpenKG 大模型专辑 导读 知识图谱和大型语言模型都是用来表示和处理知识的手段。大模型补足了理解语言的能力&#xff0c;知识图谱则丰富了表示知识的方式&#xff0c;两者的深度结合必将为人工智能提供更为全面、可靠、可控的知识处理方法。在这一背景下&#xff0c;OpenKG组织…