线性DP-----(从某点走到某点求最值问题)

news2025/1/16 18:00:19

线性DP

线性dp问题是dp问题中比较简单的问题,通常一个状态转移方程就可以搞定,线性dp通常求最大值,最小值问题,下面介绍线性dp中从某点走到某点最值问题。

第一类问题(走一遍)

该类问题只走一遍,动态规划中用到的数组f(i,j)含义就是到达(i,j)点得到的最优解

例题1—数字三角形

问题描述

数字三角形题目链接

在这里插入图片描述

在这里插入图片描述

解题思路

此类题目关键在于找出动态转移方程,找出动态转移方程的关键在于分析,某点的移动方向,通常一个点只能向几个方向移动,我们在列出动态转移方程时,先确定某一点可以从那几个方向来,将几个方向的最优解进行比较选出最大或最小值,作为该点的最优解。

根据此题,从第一层一直走向最后一层所以,每次有两个放下,左下方和右下方,所以某点只可能,从左上方和右上方移动过来,进而比较左上方和右上方的最优值,得出动态转移方程!
f[i][j]=max(f[i-1][j],f[i-1][j-1])+w[i][j]

边界初始化问题
边界初始化问题一般是这类题目,需要预先处理数组初值,防止在动态转移方程比较过程中出错,比如这道题求解最大值,在边界部分都需要初始化最小值-INF(-0x7f7f7f7f)即可,如果叫不准边界,则将全部放大处理到n,后面代码有详细解释这样用的好处

运行代码

#include<bits/stdc++.h>
#define ll long long 
#define INF 0x7f7f7f7f

using namespace std;
const int maxn=510;
int n,m,ans;
int f[maxn][maxn];
int w[maxn][maxn];


int main(){
	

	cin>>n;//读入层数
	
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++){
			cin>>w[i][j]; 
		} 
	} 
	//边界初始化 
	for(int i=0;i<=n;i++){ //i可以从1开始,叫不准就从0开始 
		for(int j=0;j<=n;j++){ //这个j实际可以初始到i,如果叫不准放大处理到n 
			f[i][j]=-INF;
		}
	} 
	f[1][1]=w[1][1]; //第一层 
   	for(int i=2;i<=n;i++){
		for(int j=1;j<=i;j++){
	         f[i][j]=max(f[i-1][j],f[i-1][j-1])+w[i][j]; //动态转移方程 
		} 
	} 
	//在最后一层找到最大值 
	ans=-INF; 
	for(int i=1;i<=n;i++){
		ans=max(ans,f[n][i]); 
	} 
	
	cout<<ans<<endl; 
	return 0;
}

例题2—摘花生

问题描述

题目链接

在这里插入图片描述

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

解题思路

题目中只能向东走和向南走,实际上就是向右走和向下走。所以某点只能从它的左侧和上侧移动过来所以比较,他的左侧和上侧的最优值即可。

边界问题:这道题由于没有负数,所以全局数组初始值为0,所以不用初始化处理边界问题

运行代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxn=110;

int ans,m,n,p;
int  a[maxn][maxn];
int dp[maxn][maxn];


int main(){
	
	int t;
	cin>>t;
	
	while(t--){
		cin>>m>>n;
		for(int i=1;i<=m;i++){
			for(int j=1;j<=n;j++){
				cin>>a[i][j];
			}
		}
		
		for(int i=1;i<=m;i++){
			for(int j=1;j<=n;j++){
				dp[i][j]=max(dp[i][j-1],dp[i-1][j])+a[i][j];//动态转移方程 
			}
		}
		cout<<dp[m][n]<<endl;
	}

	
	return 0;
} 

第二类问题(走两遍)

该类问题去的时候走一遍,回来的时候走一遍,我们可以统一为,从两个人从同一初始点同时出发,一起走到终点。 该类问题的遍历,正常想是枚举(x1,y1)和(x2,y2)那么需要四重for循环遍历所以情况,复杂度非常高,我们对其进行简化, 引出一个概念,两人同时走了k步,第一个人走了k步,与第二个人走了k步,这样做有什么好处呢? 这类问题经常处理两人路线有交集,两人经过同一位置,我们需要特殊处理这种位置,关键在于如何找出来呢,当两人位于同一位置,那么他们走过的步数一定相同,都为k步,那么我在枚举出两人的横坐标,就可以得出两人的纵坐标,y=k-x (题目要求从左上角走到右下角,只能向右或下走) 通过引入同时走k步概念,也就只需要三重for循环就可以达到四重for循环的效果。

动态转移方程分析
通过上面分析,得出通过k步三个for循环枚举出,第一个人和第二个人同时走k步,两人位于不同位置或者相同位置情况,我们先定义一下dp所用到的数组含义f(k,i1,i2) k是同时走k步,i1,i2为二人的横坐标,那么到达该点,可以通过四种情况到达,第一种两人同时向下移动,第二种,第一个人向右,第二个人向下,第三种第一个人向下,第二个人向右,第四种,两人同时向下,通过以上四种情况到达该点。

通过上面分析动态转移方程为:
f(k,i1,i2)=max/min(f(k-1,i1-1,i2-1),f(k-1,i1,i2-1),f(k-1,i1-1,i2),f(k-1,i1,i2))+w(i1,j1)+w(i2,j2)
i1,i2为两人的横坐标,j1,j2为两人的纵坐标 j1=k-i1,j2=k-j2

例题三—方格取数

题目描述

题目链接
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

题目分析

题目说从左上角,走到右下角,在从右下角走到左上角,可以简化为两人同时从左上角走到右下角。关在在于处理路线交集部分,交集部分只能加上一个权值,根据上面的分析我们得出动态转移方程
f(k,i1,i2)=max/min(f(k-1,i1-1,i2-1),f(k-1,i1,i2-1),f(k-1,i1-1,i2),f(k-1,i1,i2))+w(i1,j1)+w(i2,j2)

在这里插入图片描述

边界处理
由于求最大值,并且权值均大于0所以不需要额外处理

运行代码

#include<bits/stdc++.h>
#define ll long long 
#define INF 0x7f7f7f7f

using namespace std;
const int maxn=10;
int n,m;
int dp[maxn*2][maxn][maxn];
int w[maxn][maxn];


int main(){
	
	cin>>n;
	
	while(1){ 
		int x,y,v;
		cin>>x>>y>>v;
		if(x==0&&y==0)break;
		w[x][y]=v;
	}
	
	for(int k=1;k<=n*2;k++){
		for(int i1=1;i1<=n;i1++){
			for(int i2=1;i2<=n;i2++){
				 int j1=k-i1,j2=k-i2;
				 int t;
				 if(j1>=1&&j1<=n&&j2>=1&&j2<=n){//判断是否越界 
				 	 t=w[i1][j1];
				 	 if(i1!=i2)t+=w[i2][j2];//不在同一点 
				 	 
				 	 int &x=dp[k][i1][i2];//这样写方便 
				 	 x=max(x,dp[k-1][i1-1][i2-1]+t);//下下 
				 	 x=max(x,dp[k-1][i1-1][i2]+t);//下右 
				 	 x=max(x,dp[k-1][i1][i2-1]+t);//右下 
				 	 x=max(x,dp[k-1][i1][i2]+t);//右右	
				 }
			}
		}
	}
	cout<<dp[n*2][n][n];
	
	
	
	
	
	return 0;
}

例题四—传纸条

题目链接

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

题目分析

这道题,只需要注意,每人只能传一次,也就是两条路线不能有交集,两人不能在同一坐标内。特殊判断一下即可,动态转移方程和上一道题完全相同

实现代码

#include<bits/stdc++.h>
#define ll long long 
#define INF 0x7f7f7f7f

using namespace std;
const int maxn=10;
int n,m;
int dp[maxn*2][maxn][maxn];
int w[maxn][maxn];


int main(){
	
	cin>>n;
	
	while(1){ 
		int x,y,v;
		cin>>x>>y>>v;
		if(x==0&&y==0)break;
		w[x][y]=v;
	}
	
	for(int k=1;k<=n*2;k++){
		for(int i1=1;i1<=n;i1++){
			for(int i2=1;i2<=n;i2++){
				 int j1=k-i1,j2=k-i2;
				 int t;
				 if(j1>=1&&j1<=n&&j2>=1&&j2<=n){//判断是否越界 
				 	 t=w[i1][j1];
				 	 if(i1!=i2)t+=w[i2][j2];//不在同一点 
				 	 
				 	 int &x=dp[k][i1][i2];//这样写方便 
				 	 x=max(x,dp[k-1][i1-1][i2-1]+t);//下下 
				 	 x=max(x,dp[k-1][i1-1][i2]+t);//下右 
				 	 x=max(x,dp[k-1][i1][i2-1]+t);//右下 
				 	 x=max(x,dp[k-1][i1][i2]+t);//右右	
				 }
			}
		}
	}
	cout<<dp[n*2][n][n];
	
	
	
	
	
	return 0;#include<bits/stdc++.h>
#define ll long long 
#define INF 0x7f7f7f7f

using namespace std;
const int maxn=50;
int n,m;
int dp[maxn*2][maxn][maxn];
int w[maxn][maxn];


int main(){
	
	cin>>m>>n;
	
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){
			cin>>w[i][j];
		}
	}
	
	for(int k=2;k<=m+n;k++){
		for(int i1=1;i1<=m;i1++){
			for(int i2=1;i2<=m;i2++){
				int j1=k-i1,j2=k-i2;
				if(j1>=1&&j1<=n&&j2>=1&&j2<=n){
					 int t=w[i1][j1]+w[i2][j2];
					 if(i1!=i2||k==2||k==n+m){ //只能传一次,起始点,终点位置
					  int &x=dp[k][i1][i2];
					 x=max(x,dp[k-1][i1-1][i2-1]+t);//下下 
					 x=max(x,dp[k-1][i1][i2-1]+t);//右下 
					 x=max(x,dp[k-1][i1-1][i2]+t);//下右 
					 x=max(x,dp[k-1][i1][i2]+t);//右右 
			     	} 
				}
			}
		}
	}
	cout<<dp[m+n][m][m];
	
	
	
	
	
	
	return 0;
}

总结

从某点走到某点是线性dp的经典问题,处理该问题需要找到合适的动态转移方程,并且对边界进行处理,笔者对此类问题进行了分类,分为走一次和走两次问题。走两次问题又对动态转移数组进行的简化处理,整体解释的比较详细,感谢大家观看,有问题评论区见。

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

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

相关文章

分享88个JavaScript源码,总有一款适合您

JavaScript源码 分享88个JavaScript源码&#xff0c;总有一款适合您 JavaScript源码下载链接&#xff1a;https://pan.baidu.com/s/1guiYWOPKdP1zNW7T8P0caQ?pwd6666 提取码&#xff1a;6666 采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 下面是文件的名字&#xf…

jinja2 循环计数内置变量loop

变量内容loop.index循环迭代计数&#xff08;从1开始&#xff09;loop.index0循环迭代计数&#xff08;从0开始&#xff09;loop.revindex循环迭代倒序计数&#xff08;从len开始&#xff0c;到1结束&#xff09;loop.revindex0循环迭代倒序计数&#xff08;从len&#xff0d;1…

【正点原子FPGA连载】 第十八章双目OV5640摄像头HDMI显示实验 摘自【正点原子】DFZU2EG/4EV MPSoC 之FPGA开发指南V1.0

1&#xff09;实验平台&#xff1a;正点原子MPSoC开发板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id692450874670 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第十八章双目OV5…

jsp题库管理系统Myeclipse开发sqlserver数据库web结构java编程计算机网页项目

一、源码特点 jsp 题库管理系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开 发&#xff0c;数据库为sqlserver&#xff0c;使…

Kafka集群安装

Apache kafka是由Apache软件基金会开发的一个开源流处理平台&#xff0c;由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统&#xff0c;是消息中间件的一种&#xff0c;用于构建实时数据管道和流应用程序。Kafka官网&#xff1a;http://kafka.apache.org/安装环…

1-连续系统PID的Simulink仿真

以二阶线性传递函数。为被控对象&#xff0c;进行模拟PID控制。在信号发生器中选择正弦信号&#xff0c;仿真时取&#xff0c;&#xff0c;&#xff0c;输入指令为&#xff0c;其中A1.0,F0.20Hz。采用ODE45迭代方法&#xff0c;仿真时间为10s。PID控制器由Simulink下的工具箱提…

【Ansible】Ansible Jinja2 模板

Ansible Jinja2 模板 文章目录Ansible Jinja2 模板一、Ansible Jinja2 模板背景介绍二、JinJa2 模块1.JinJa2 是什么&#xff1f;2.Jinja2 必知会3.Jinja2 逻辑控制三、如何使用模板四、 实例演示一、Ansible Jinja2 模板背景介绍 目前 nginx 的配置文件在所有的服务器上都是相…

六种常见系统架构

六种常见系统架构 - 基础篇目录概述需求&#xff1a;设计思路实现思路分析1.URL管理2.微服务架构3.四、微服务架构4.多级缓存架构参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,m…

【Unity学习笔记】[Unity中文课堂教程] C#中级编程代码

【Unity学习笔记】[Unity中文课堂教程] C#中级编程代码 最近想补一补C#基础&#xff0c;Unity官方的C#中级编程教程质量很高&#xff0c;于是开个帖子把跟着敲记录了部分价讲解和我自己的理解的代码存在这 原课程链接&#xff1a;添加链接描述 https://www.bilibili.com/video…

Java字符流(FileReader/FileWriter)

文章目录概念FileReader字符输入流相关方法和构造器FileWriter字符输出流相关方法和构造器为什么用完不close或flush&#xff0c;会写入不到数据&#xff1f;概念 在Java中&#xff0c;使用Unicode约定存储字符。字符流自动允许我们逐字符读/写数据&#xff0c;有助于执行16位…

2023年网络爬虫实训(第五天)

任务1&#xff1a;掌握re.match和re.search的用法,完成课堂代码.掌握基础通配符的用法如\w \s \d [] * ^ $.并完成作业4. 1.re.match() re.match&#xff08;&#xff09;的是从头匹配一个符合规则的字符串&#xff0c;从起始位置开始匹配&#xff0c;匹配成功返回一个对象&…

1.力扣刷题之二分查找

题目: 704. 二分查找 - 力扣&#xff08;LeetCode&#xff09; 思路 解题 左闭右闭 左闭右开 题目: 704. 二分查找 - 力扣&#xff08;LeetCode&#xff09; 思路 这道题首先要找出关键词:有序数组&#xff0c;元素不重复&#xff1b;这些都是使用二分法的前提条件&#x…

使用Stable Diffusion和Pokedex的描述生成神奇宝贝图片

还记得我们以前使用GAN、Clip、DALL-E生成神奇宝贝的文章吗&#xff0c;现在是时候使用Stable Diffusion了 在本文中&#xff0c;我将展示如何从神奇宝贝系列不同游戏中的Pokedex条目中获取神奇宝贝描述&#xff0c;并使用Stable Diffusion根据这些藐视生成图片&#xff0c;这样…

【基数排序】 C++高效实现

题目描述 给定你一个长度为 nnn 的整数数列。 请你使用快速排序对这个数列按照从小到大进行排序。 并将排好序的数列按顺序输出。 输入格式 输入共两行&#xff0c;第一行包含整数 nnn。 第二行包含 nnn 个整数&#xff08;所有整数均在 1∼1091 \sim 10^91∼109 范围内&…

Android架构演进 · 设计模式· 为什么建议你一定要学透设计模式?

“ 【小木箱成长营】设计模式系列文章(排期中)&#xff1a; Android 架构演进 设计模式 Android 常见的 4 种创建型设计模式(上) Android 架构演进 设计模式 Android 常见的 4 种创建型设计模式(下) Android 架构演进 设计模式 Android 常见的 6 种结构型设计模式(上) An…

vue2 中组件的生命周期

目录 一、组件的生命周期 1、什么是组件的生命周期&#xff1f; 2、生命周期的阶段划分&#xff1a; &#xff08;1&#xff09;创建阶段&#xff1a;beforeCreate、created、beforeMount、mounted ​&#xff08;2&#xff09;运行阶段&#xff1a;beforeUpdate、updatev…

【顺序表】数据结构,java代码实现

前言&#xff1a; 大家好&#xff0c;我是良辰丫&#x1f353;&#x1f353;&#x1f353;&#xff0c;顺序表和数组有什么区别呢&#xff0c;我们带着这个疑问去接触顺序表&#xff0c;学习顺序表相关知识。&#x1f680;&#x1f680;&#x1f680; &#x1f9d1;个人主页&am…

商城系统春节氛围营造

春节将至&#xff0c;无论是线上还是线下&#xff0c;都在紧锣密鼓的进行春节营销&#xff0c;线下商家可以通过布置店铺&#xff0c;来营造节日氛围&#xff0c;那对于线上商城来说&#xff0c;又能从哪些方面进行氛围营造呢&#xff1f;今天&#xff0c;我们就以CRMEB Pro版系…

Spring Boot Actuator详解与深入应用(一):Actuator 1.x

《Spring Boot Actuator详解与深入应用》预计包括三篇&#xff0c;第一篇重点讲Spring Boot Actuator 1.x的应用与定制端点&#xff1b;第二篇将会对比Spring Boot Actuator 2.x 与1.x的区别&#xff0c;以及应用和定制2.x的端点&#xff1b;第三篇将会介绍Actuator metric指标…

AWVS扫描报告分析

系列文章 AWVS安装与激活 AWVS扫描Web应用程序 扫描报告分析 生成报告 1.选则我们已经扫描好的网站&#xff0c;点击它 2.点击后&#xff0c;右上角选择生成报告 3.选择生成报告的类型 4.点击生成报告 如下我们分别选择了三种规格生成了三份不同类型的报告 5.点击HTML&…