第十四周DP算法总结

2023-05-16

这周自己主要再看DP算法的博客,感觉DP这一部分内容确实比之前的都要麻烦一些,最后攻克这一部分难题还是挺好的。 这周自己总结了一些题型,以及一些方法思路,最后再把动态规划和之前的分治和贪心做一下比较。下面是详细的总结。

动态规划就是将一个复杂的问题分解成几个子问题,通过综合子问题的最优解来得到原问题的最优解。一开始我一看那个状态转移方程我就发懵,但是从最简单的题目的状态转移方程入手,发现还是可以的,能看懂一部分内容了。

动态规划的一般做题步骤,先要判断是不是有有重叠子问题和最优子结构,然后再划分阶段,分成若干个小问题,然后确定状态和状态变量,列出状态转移方程(数组形式),接下来找出边界条件,最后递推求解即可。记忆化搜索的思路也是贯穿在了这部分很多题目当中,代码效率得到很大提高。

最大连续子序列和问题,这一类问题用枚举或者前缀和的方式肯定不行的,复杂度高。列出状态转移方程,dp[i]=max{A[i],dp[i-1]+A[i]},一开始我是没看懂的,但是仔细一想还是挺巧秒的,用dp[i]表示以A[i]作为末尾的连续序列的最大和,然后求解dp数组。考虑到只有两种情况,一个情况是最大和的连续序列只有一个元素,另一种情况是这个连续序列有很多元素,这个时候最大和就是以前面一个元素为结尾的连续子段的最大和加上当前的元素,就是dp[i-1]+A[i]。这两种情况都讨论完了,求解最大值就是取这两种情况的最大值就行了,然后列出状态转移方程dp[i]=max{A[i],dp[i-1]+A[i]}就很好理解了,总体来说这类题目还是挺好理解的。

数塔问题,题意是说,一些数字排成数塔的形状,第一层有一个数字,第二层有两个数字,以此类推,从第一层走到第n层,每次只能走下一层连接的两个数字中的一个,最后将经过的数字相加,问得到的最大值是多少。首先确定的是,这个题一定有最优解。枚举从一个数字出发到达底层的所有路径时,就把这个最大和记录下来,可以避免重复计算。可以让dp[i][j]表示从第i行第j列开始到达底层得到的最大和,因为是要求从顶层开始的,所以dp[1][1]就是最终解。因为一个数字下面有两个分支,所以要取其中最大的一个,再加上这个数字就是目前得到的较大值,由此就可以列出状态转移方程,dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+f[i][j]。底层为边界,所以可以从最底层各位置的dp值开始,开始不断的网上求出每一层的dp值,然后一直走到最上边的时候,就得到了dp[1][1]。

最长回文子串问题,这个问题是说,给定一个字符串S,求这个最长回文子串的长度。题意很好理解,但是细节多。 可以令dp[i][j]表示S[i]到S[j]所表示的子串是否是回文子串,是就为1,不是就为0,状态转移情况就可以考虑到有两种情况,如果S[i]和S[j]相等的话,只要S[i+1]到S[j-1]时回文子串,那么S[i]到S[j]就是回文子串,否则就不是了,反之,如果S[i]和S[j]不相等的话,肯定不是回文子串。那么状态转移方程就可以写成dp[i][j]=dp[i+1][j-1],当S[i]等于S[j]的时候;dp[i][j]=0,当S[i]不等于S[j]的时候。需要注意的是,为了确保状态可以转移,要从边界出发,按子串的长度和初始位置进行枚举,确保状态可以转移,按照这个思路就可以解决这个问题了。

最优三角形剖分问题,题意是说给定n个点的坐标,先问这些点是否能组成一个凸包,如果是凸包,用不相交的线来切这个凸包使得凸包只由三角形组成,根据cost(i,j)=|xi+xj|*|yi+yj|%p算切线的费用,问最少的切割费用。首先判断多边形是不是凸的,判断凸包的点数和给定的点数是不是一样多就可以了。然后就是最优三角形剖分,接下来要用n-3条直线将凸包切成n-2个三角形,然后具体实现的过程,可以先选择一个基准边,两端点标号为1和n,然后再选择一个点S,这样就在这个图形里边先形成了一个三角形,整个图形就被分成了3部分,然后中间这个新建立的三角形先不用管了,旁边两部分同样的方法进行分割,最后整个图形就被划分好了,全是由三角形组成,逐渐的将凸包分成一个个的子凸包并计算相应的费用,最后再更新到点1和点n为起始点的凸包就可以了。用Dp[i][j]表示以i为起点,j为终点的凸包被切割成一个个小三角形所需要的费用,列出状态转移方程为dp[i][j]=min(dp[i][k]+dp[k][j]+cost[i][k]+cost[k][j])求解就可以了。

核心部分代码:

int Graham(point *p,int n) {

	int i;
	sort(p,p + n,cmp);
	save[0] = p[0];
	save[1] = p[1];
	int top = 1;
	for(i = 0;i < n; i++){
 
		while(top && xmult(save[top],p[i],save[top-1]) >= 0)top--;
		save[++top] = p[i];
	}
 
	int mid = top;
	for(i = n - 2; i >= 0; i--){
 
		while(top>mid&&xmult(save[top],p[i],save[top-1])>=0)top--;
		save[++top]=p[i];
	}
	return top;
}
int Count(point a,point b) {
 
	return (abs(a.x + b.x) * abs(a.y+b.y)) % m;
}
 
 
int main()
{
	int i,j,k,r,u;

	while (scanf("%d%d",&n,&m) != EOF) {
		for (i = 0; i < n; ++i)
			scanf("%d%d",&p[i].x,&p[i].y);
		int tot = Graham(p,n);	
		if (tot < n) printf("I can't cut.\n");
		else 
			memset(cost,0,sizeof(cost));
			for (i = 0; i < n; ++i)
				for (j = i + 2; j < n; ++j)
					cost[i][j] = cost[j][i] = Count(save[i],save[j]);
	
			for (i = 0; i < n; ++i) {
		
				for (j = 0; j < n; ++j)
					dp[i][j] = INF;
				dp[i][(i+1)%n] = 0;
			}
			for (i = n - 3; i >= 0; --i)	
				for (j = i + 2; j < n; ++j) 
					for (k = i + 1; k <= j - 1; ++k)
						dp[i][j] = min(dp[i][j],dp[i][k]+dp[k][j]+cost[i][k]+cost[k][j]);
 
			printf("%d\n",dp[0][n-1]);
		}
	}
}

石子合并问题,这类题目题型有很多,其中一类就是说有N堆石子,现要将石子有序的合并成一堆,每次只能移动相邻的2堆石子合并,合并花费为新合成的一堆石子的数量,问将这N堆石子合并成一堆的总花费最小或者最大。这个题自己没大看懂,大体的解题方法就是用矩阵连乘的方式来解决,用dp[i][j]表示第i到第j堆石子合并的最优值,sum[i][j]表示第i到第j堆石子的总数量,列出状态转移方程,当i等于j的时候,dp[i][j]=0,当i不等于j的时候,dp[i][j]=min(dp[i][k],dp[k+1][j])+sum[i][j]。然后这个题也有一个优化的思路,就是用平行四边形进行优化,枚举分割点的时候,就直接枚举p[i][j-1]到p[i+1][j]这个区间,而不用枚举[i,j],降低复杂度。(参考题解)

优化代码如下:

int getMinval()
{
    for(int i=1; i<=n; i++)
    {
        dp[i][i] = 0;
        p[i][i] = i;
    }
    for(int len=1; len<n; len++)
    {
        for(int i=1; i+len<=n; i++)
        {
            int end = i+len;
            int tmp = INF;
            int k = 0;
            for(int j=p[i][end-1]; j<=p[i+1][end]; j++)
            {
                if(dp[i][j] + dp[j+1][end] + sum[end] - sum[i-1] < tmp)
                {
                    tmp = dp[i][j] + dp[j+1][end] + sum[end] - sum[i-1];
                    k = j;
                }
            }
            dp[i][end] = tmp;
            p[i][end] = k;
        }
    }
    return dp[1][n];
}

总结:

要用动态规划解决问题的话,必须拥有重叠子问题和最优子结构。

分治与动态规划相同之处在于,它们都是将问题分解为子问题,然后进行合并得到原问题的解。不同之处在于,分治的子问题没有重叠,动态规划有重叠子问题,而且分治解决的问题不一定最优,但是动态规划解决的问题一定是最优化问题。

再将贪心和动态规划比较一下吧。首先原来的问题一定要有最优子结构,贪心直接选择一个子问题求解,通过局部最优达到整体最优。动态规划会考虑所有子问题,选择最优结果,即使暂时没有被选择的子问题,后期也可能会再考虑,也有可能是最优解,所以最后一定得到最优解。

总体来说吧,虽然动态规划难,但是非常好用,用途广,得到的一定是最优解。设计好状态和写出状态转移方程是非常重要的,而且一些大佬的博客写的状态转移方程都非常长,但是还是得多理解呀,理解了那个过程,状态转移方程就理解得就相对容易一些了。

这学期acm的学习也快接近尾声了,在最后阶段更要坚持下去,不掉链子,保持良好的学习节奏,天气炎热更要沉心静气的去学习,继续认真的完成每一次任务!

下周继续努力!!!
 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

第十四周DP算法总结 的相关文章

  • git 的使用方法 (下 - 远程仓库和图形化)

    目录 前言 xff1a 一 什么是协同开发二 Gitee 使用协同开发1 首先注册一个码云账号2 新建一个仓库3 根据下图把新建仓库设置为开源4 在远端合并分支的方法5 链接 git 远程6 提交 xff08 同步 xff09 远程7 远程
  • docker从私有镜像库pull/push镜像问题:Error response from daemon: Get https://xxxx.com/: x509: certificate signe...

    docker从私有镜像库pull push镜像问题 xff1a Error response from daemon Get https harbor op xxxx com v2 x509 certificate signed by un
  • Vue3 中组件的使用(上)

    目录 前言 xff1a 一 什么是组件二 注册组件1 全局注册2 局部注册 二 传递数据 父 gt 子 1 字符串数组的形式2 对象的形式 三 组件事件 子 gt 父 1 字符串数组式声明自定义事件2 子组件 触发组件事件3 父组件 监听子
  • Vue3 中组件的使用(下)

    目录 前言 xff1a 一 透传属性和事件1 如何 透传属性和事件 2 如何禁止 透传属性和事件 3 多根元素的 透传属性和事件 4 访问 透传属性和事件 二 插槽1 什么是插槽2 具名插槽3 作用域插槽 三 单文件组件CSS功能1 组件作
  • Vue3 中的模板语法

    目录 前言一 什么是模板语法 xff1f 二 内容渲染指令1 v text2 插值表达式3 v html 三 双向绑定指令1 v model2 v model的修饰符 四 属性绑定指令1 动态绑定多个属性值2 绑定class和style属性
  • 微信小程序基础介绍

    目录 前言 xff1a 一 什么是微信小程序二 微信小程序的发展历史三 微信小程序的优缺点四 与其他相关概念的区别与H5的区别与公众号 订阅号 服务号 企业微信的区别 五 小程序的环境六 初始化项目七 小程序单位八 导航栏配置九 模板引用十
  • 使用 uni-app 完成左滑效果

    目录 前言 xff1a 一 效果展示二 代码地址三 实现思路四 效果完成步骤1 html 代码2 js代码3 css 代码4 后台代码 总结 xff1a 前言 xff1a 左滑显示编辑 删除 或者 置顶之类的功能我们经常要实现 xff0c
  • React 入门(超详细)

    目录 前言 xff1a 一 React 简介1 什么是 React2 React 的特点3 React 高效的原因4 React 官网5 React的主要原理6 Facebook为什么要建造React 二 React 的基本使用1 基础代码
  • React 面向组件编程(上)

    目录 前言 xff1a 一 组件的基本理解和使用1 函数式组件2 类式组件3 注意事项4 渲染函数式组件标签的基本流程5 渲染类组件标签的基本流程 二 组件三大核心属性 1 xff1a state1 代码示例2 效果展示3 注意4 设置状态
  • React 面向组件编程(下)

    目录 前言 xff1a 一 受控组件与非受控组件1 受控组件2 非受控组件3 效果展示4 总结 xff1a 二 组件的生命周期1 对生命周期的理解2 生命周期的三个阶段 xff08 旧 xff09 3 生命周期的三个阶段 xff08 新 x
  • React应用(基于React脚手架)

    目录 前言 xff1a 一 使用create react app创建react应用1 什么是 react 脚手架 xff1f 2 创建 cli 脚手架方式13 创建 cli 脚手架方式24 npx 5 react脚手架项目结构6 功能界面的
  • Tesseract(识别验证码)

    Tesseract windows 下的安装及简单应用 1 Tesseract安装以及简介 阻碍我们爬虫的 有时候正是在登录或者请求一些数据时候的图形验证码 因此这里我们讲解一种能将图片翻译成文字的技术 将图片翻译成文字一般被称为光学文字识
  • POJ 2893 M × N Puzzle——八数码有解条件

    题意 xff1a 给定M N的数码图 xff0c 问能否移动到最终状态 分析 有解的判定条件可见 八数码有解条件 值得一提的是 xff0c 这道题求逆序对卡树状数组 xff0c 只能用归并排序 include lt cstdio gt in
  • 【c语言典例一】十进制的数转化为二进制和八进制

    首先 xff0c 介绍十进制转二进制的方法 xff1a 十进制整数转换为二进制整数十进制整数转换为二进制整数采用 34 除2取余 xff0c 逆序排列 34 法 具体做法是 xff1a 用2整除十进制整数 xff0c 可以得到一个商和余数
  • C语言字符个数统计

    输入一行字符 xff08 字符个数小于80 xff09 xff0c 这行字符包括小写字母 xff0c 大写字母 xff0c 数字 xff0c 空格等其他可打印符号 请统计各字母的个数 xff0c 小写字母和大写字母统计于小写字母上 xff0
  • 【STC15单片机】按键&静态数码管显示0~9

    目录 数码管工作原理 共阳极数码管段码表 共阴极数码管段码表 矩阵键盘 amp 数码管综合应用 单片机型号说明 xff1a IAP15F2K61S2 新建工程时单片机型号选择STC15F2K60S2 本开发板支持的显示器件 xff1a LE
  • 字典查询python

    有字典 dict1 61 39 赵广辉 39 39 13299887777 39 39 特朗普 39 39 814666888 39 39 普京 39 39 522888666 39 39 吴京 39 39 13999887777 39 x
  • python中的序列(列表、元组、字符串)的切片操作

    目录 一 序列 二 序列常用操作 切片 注意 演示 一 序列 序列是指 内容连续 有序 xff0c 可使用下标索引的一类数据容器 列表 元组 字符串 xff0c 均可以可以视为序列 二 序列常用操作 切片 序列支持切片 xff0c 即 列表
  • 四,面向对象 ——类与对象

    面向对象的三大特征 xff1a 封装型 xff0c 继承性 xff0c 多态性 xff08 可能有些还会说有抽象性 xff09 类 xff08 class 和对象 xff08 object 是面向对象程序设计方法中最核心的概念 面向对象的两
  • POJ - 2823 滑动窗口

    题目 xff1a 给一个长度为 NN 的数组 xff0c 一个长为 KK 的滑动窗体从最左端移至最右端 xff0c 你只能看到窗口中的 KK 个数 xff0c 每次窗体向右移动一位 找出窗体在各个位置时的最大值和最小值 思路 xff1a 网

随机推荐

  • C语言十进制转八进制

    输入 12 输出 14 include lt stdio h gt int main int n scanf 34 d 34 amp n int i 61 0 int a 100 int count while 1 a i 61 n 8 n
  • Docker 中,对 MySQL配置文件修改

    步骤 1 docker ps span class token punctuation span a 查看docker内的镜像 2 进入容器 docker exec it 容器ID bin bash 3 找到MySQL的配置文件 mysql
  • 【Linux学习】进程间通信——system V(共享内存 | 消息队列 | 信号量)

    x1f431 作者 xff1a 一只大喵咪1201 x1f431 专栏 xff1a Linux学习 x1f525 格言 xff1a 你只管努力 xff0c 剩下的交给时间 xff01 进程间通信 共享内存 消息队列 信号量 x1f3c0 共
  • python_tkinter组件摆放方式

    1 最小界面组成 导入tkinter模块 import tkinter 创建主窗口对象 root 61 tkinter Tk 设置窗口大小 最小值 xff1a 像素 root minsize 300 300 创建一个按钮组件 btn 61
  • conda create -n yolov5_py36 python=3.6 出现Solving environment: failed”报错的解决办法

    该错误通常意味着Conda无法解决您的环境依赖关系 以下是可能的解决方案 xff1a 检查您的网络连接 xff1a 确保您的计算机已连接到互联网 xff0c 并且没有任何防火墙或代理阻止Conda访问所需的资源 清除Conda缓存 xff1
  • Ubuntu 20.04 系统迁移

    一 前言 现实工作中需要在Intel NUC上装一个Ubuntu 20 04系统 xff0c 并运行ROS以及相关的很多功能包 xff0c 但如果直接安装新新系统 xff0c 之前的大量环境变量要重新去配置 xff0c 所以考虑说将原先的U
  • 求十个数中的最大值流程图(思路之一)

  • 求100以内的偶数和

    一 文字描述 1 定义两个整型变量sum xff0c i xff1b 2 把0赋值给sum xff0c 2赋值给i xff1b 3 使sum 61 sum 43 i xff1b 4 如果i xff1c 61 100 xff0c 则返回第3步
  • 数据库总结(六):创建与使用存储过程

    目录 任务6 1 创建简单存储过程 1 PL SQL的变量 2 PL SQL的运算符及表达式 3 PL SQL的控制语句 4 MySQL的存储过程 任务6 2 创建带输入参数的存储过程 1 MySQL带输入参数的存储过程的创建 2 调用存储
  • 数据库总结(七):创建与使用触发器

    目录 任务7 1 创建触发器 1 触发器概述 2 创建触发器 任务7 2 查看及删除触发器 1 查看触发器 2 删除触发器 END 数据表中为了保证数据的完整性或执行其他特殊规则 xff0c MySQL除了提供约束之外 xff0c 还提供了
  • 数据库总结(8):数据库的安全性维护

    一 创建语句 1 添加数据库用户 insert into user host user password ssl cipher x509 issuer x509 subject values 主机号 用户名 password 密码 2 up
  • 『Java练习』面向对象程序练习

    编写一个类Calculate1 xff0c 实现加 减两种运算 xff0c 然后 xff0c 编写另一个派生类Calculate2 xff0c 实现乘 除两种运算 package object oriented development wo
  • C语言 冒泡法 比大小 从键盘输入10个整数,从他们从小到大输出的答案

    C语言 从键盘输入10个整数 xff0c 从他们从小到大输出的答案 方法 xff1a 冒泡法 通过举例子来介绍什么是冒泡法 xff0c 怎么比大小 xff1b 讲一下思路 xff1a 随便三个数 xff1a 5 xff0c 7 xff0c
  • 三点弯曲的有限元仿真

    0 概述 什么是三点弯曲 xff1f 三点弯曲变形有哪些特点 xff1f 三点弯曲仿真有哪些需要注意的地方 xff1f xff08 1 xff09 三点弯曲试验是将截面为矩形或圆形的试样放在弯曲装置上 xff0c 调整跨距 xff0c 在试
  • 视图篇——表格视图UITableView及控制器UITableViewController

    来自http www cnblogs com lovecode articles 2238309 html UITableViewController表格视图控制器 UITableViewController类继承自UIViewContro
  • JS 定时对象时,key加中括号表示什么意思

    对象key 加中括号是 取中括号中变量的内容 当做对象的key使用 xff0c 不加中括号 xff0c 则直接用该字符串当作对象的key 例如如下代码 xff1a var name 61 39 keyn 39 var a 61 name 3
  • 结构体案例2

    设计一个英雄的结构体 xff0c 包括成员姓名 xff0c 年龄 xff0c 性别 xff1b 创建结构体数组 xff0c 数组中存放5名英雄 通过冒泡排序 xff0c 将数组中的英雄按年龄进行升序排列 xff0c 最终打印排序后的结果 i
  • 第二周博客总结

    既然自己选择了学习算法 xff0c 便会一直坚持下去 xff0c 完成自己既定的目标 xff01 这一周下来 xff0c 按照自己既定的计划 xff0c 自己利用课余时间看深入浅出这本书 从第八章的初涉算法一直看到了第十七章的集合 xff0
  • 第四周ACM博客总结

    这一周基本对算法知识进行了一次细致的阅读 xff0c 自己也对算法知识有了更深一步的了解 这一周自己先将上周剩下的一点STL的内容补上了 xff0c 这些容器之间相似的地方有很多 xff0c 但都有各自的优点所在 xff0c 需要结合题目特
  • 第十四周DP算法总结

    这周自己主要再看DP算法的博客 xff0c 感觉DP这一部分内容确实比之前的都要麻烦一些 xff0c 最后攻克这一部分难题还是挺好的 这周自己总结了一些题型 xff0c 以及一些方法思路 xff0c 最后再把动态规划和之前的分治和贪心做一下