【动态规划】【C++算法】741摘樱桃

news2024/11/14 19:37:57

作者推荐

【动态规划】【数学】【C++算法】18赛车

涉及知识点

动态规划

LeetCode741 摘樱桃

给你一个 n x n 的网格 grid ,代表一块樱桃地,每个格子由以下三种数字的一种来表示:
0 表示这个格子是空的,所以你可以穿过它。
1 表示这个格子里装着一个樱桃,你可以摘到樱桃然后穿过它。
-1 表示这个格子里有荆棘,挡着你的路。
请你统计并返回:在遵守下列规则的情况下,能摘到的最多樱桃数:
从位置 (0, 0) 出发,最后到达 (n - 1, n - 1) ,只能向下或向右走,并且只能穿越有效的格子(即只可以穿过值为 0 或者 1 的格子);
当到达 (n - 1, n - 1) 后,你要继续走,直到返回到 (0, 0) ,只能向上或向左走,并且只能穿越有效的格子;
当你经过一个格子且这个格子包含一个樱桃时,你将摘到樱桃并且这个格子会变成空的(值变为 0 );
如果在 (0, 0) 和 (n - 1, n - 1) 之间不存在一条可经过的路径,则无法摘到任何一个樱桃。
示例 1:
输入:grid = [[0,1,-1],[1,0,-1],[1,1,1]]
输出:5
解释:玩家从 (0, 0) 出发:向下、向下、向右、向右移动至 (2, 2) 。
在这一次行程中捡到 4 个樱桃,矩阵变成 [[0,1,-1],[0,0,-1],[0,0,0]] 。
然后,玩家向左、向上、向上、向左返回起点,再捡到 1 个樱桃。
总共捡到 5 个樱桃,这是最大可能值。
示例 2:
输入:grid = [[1,1,-1],[1,-1,1],[-1,1,1]]
输出:0
参数范围
n == grid.length
n == grid[i].length
1 <= n <= 50
grid[i][j] 为 -1、0 或 1
grid[0][0] != -1
grid[n - 1][n - 1] != -1

动态规划

起程和返程可能进过同一地点,此处的樱桃只能摘一次。转换一下思路:假定有两个机器人,第一个机器按起程路线走,第二个机器人按返程路线反向走。由于只能向右下,所以不会存在环,也不会往回走。假定移动step次后,第一个机器人在r1行,第二个机器人在r2行,则第一个机器人在第step-c1列,第二个机器人在step-c2列。同一格行列号相同 ==> 行列号之和(step)相同 ==> 不同step,一定不是同一格子。
小技巧: setp相同时,只需要判断行号或列号是否相同。

动态规划的填表顺序

时间复杂度:O((n*2)nn) 三层循环,第一层从小到大枚举step;第二层枚举第一个机器人所在行,第二层枚举第二个机器人所在行。

动态规划的状态表示

pre[r1][r2]表示 step步后,机器人一在r1,机器人二在r2 已经收获的最大樱桃数。
dp[nr1][nr2]表示 step+1步后,机器人一在nr1,机器人二在nr2 已经收获的最大樱桃数。

动态规划的转移方程

int i2 = (nr1 == nr2) ? 0 : grid[nr2][nc2];//如果两个机器人 在同一位置不重复计算
							dp[nr1][nr2] = max(dp[nr1][nr2],pre[r1][r2] + grid[nr1][nc1] + i2 );

动态规划的初始状态

pre[0][0] = grid[0][0];

动态规划的返回值

return (-1==pre.back().back())?0: pre.back().back();

代码

封装类

class CEnumGridEdge
{
public:
	void Init()
	{
		for (int r = 0; r < m_r; r++)
		{
			for (int c = 0; c < m_c; c++)
			{
				Move(r, c, r + 1, c);
				Move(r, c, r - 1, c);
				Move(r, c, r, c + 1);
				Move(r, c, r, c - 1);
			}
		}
	}
	const int m_r, m_c;
protected:
	CEnumGridEdge(int r, int c) :m_r(r), m_c(c)
	{
		
	}
	void Move(int preR, int preC, int r, int c)
	{
		if ((r < 0) || (r >= m_r))
		{
			return;
		}
		if ((c < 0) || (c >= m_c))

		{
			return;
		}
		OnEnumEdge(preR, preC, r, c);
	};
	virtual void OnEnumEdge(int preR, int preC, int r, int c) = 0;
};

复制类

class TNeiBoForGrid :  public CEnumGridEdge
{
public:	
	TNeiBoForGrid(const vector<vector<int>>& grid):m_grid(grid),
		CEnumGridEdge(grid.size(),grid.front().size())
	{
		m_vNext.assign(m_r, vector < vector<pair<int, int>>>(m_c));
		Init();
	}
	virtual void OnEnumEdge(int preR, int preC, int r, int c)
	{
		if ((-1 == m_grid[preR][preC]) || (-1 == m_grid[r][c]))
		{
			return;
		}
		if ((preR > r) || (preC > c))
		{
			return;
		}
		m_vNext[preR][preC].emplace_back(r, c);
	}
	const vector<vector<int>>& m_grid;
	vector < vector < vector<pair<int, int>>>> m_vNext;
};

核心代码

class Solution {
public:
	int cherryPickup(vector<vector<int>>& grid) {
		TNeiBoForGrid neiBo(grid);
		vector<vector<int>> pre(neiBo.m_r, vector<int>(neiBo.m_r, -1));
		pre[0][0] = grid[0][0];
		for (int step = 0; step < neiBo.m_r + neiBo.m_c - 2; step++)
		{
			vector<vector<int>> dp(neiBo.m_r, vector<int>(neiBo.m_r, -1));
			for(int r1 = max(0,step-(neiBo.m_c-1)) ; r1 <= min(step, neiBo.m_r-1);r1++ )
				for (int r2 = max(0, step - (neiBo.m_c - 1)); r2 <= min(step, neiBo.m_r-1); r2++)
				{
					if (-1 == pre[r1][r2])
					{
						continue;
					}
					const int c1 = step - r1;
					const int c2 = step - r2;
					for (const auto& [nr1, nc1] : neiBo.m_vNext[r1][c1])
					{
						for (const auto& [nr2, nc2] : neiBo.m_vNext[r2][c2])
						{
							int i2 = (nr1 == nr2) ? 0 : grid[nr2][nc2];//如果两个机器人 在同一位置不重复计算
							dp[nr1][nr2] = max(dp[nr1][nr2],pre[r1][r2] + grid[nr1][nc1] + i2 );
						}
					}
				}
			pre.swap(dp);
		}
		return (-1==pre.back().back())?0: pre.back().back();
	}
};

测试用例

template<class T>
void Assert(const T& t1, const T& t2)
{
	assert(t1 == t2);
}

template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() != v2.size())
	{
		assert(false);
		return;
	}
	for (int i = 0; i < v1.size(); i++)
	{
		Assert(v1[i], v2[i]);
	}

}

int main()
{
	vector<vector<int>> grid;
	{
		Solution sln;
		grid = { {-1} };
		auto res = sln.cherryPickup(grid);
		Assert(0, res);
	}
	{
		Solution sln;
		grid = { {0} };
		auto res = sln.cherryPickup(grid);
		Assert(0, res);
	}
	{
		Solution sln;
		grid = { {1} };
		auto res = sln.cherryPickup(grid);
		Assert(1, res);
	}
	{
		Solution sln;
		grid = { {0,1,-1},{1,0,-1},{1,1,1} };
		auto res = sln.cherryPickup(grid);
		Assert(5, res);
	}
	{
		Solution sln;
		grid = { {1,1,-1},{1,-1,1},{-1,1,1} };
		auto res = sln.cherryPickup(grid);
		Assert(0, res);
	}
	{
		Solution sln;
		grid = { {1, -1, 1, -1, 1, 1, 1, 1, 1, -1}, { -1,1,1,-1,-1,1,1,1,1,1 }, { 1,1,1,-1,1,1,1,1,1,1 }, { 1,1,1,1,1,1,1,1,1,1 }, { -1,1,1,1,1,1,1,1,1,1 }, { 1,-1,1,1,1,1,-1,1,1,1 }, { 1,1,1,-1,1,1,-1,1,1,1 }, { 1,-1,1,-1,-1,1,1,1,1,1 }, { 1,1,-1,-1,1,1,1,-1,1,-1 }, { 1,1,-1,1,1,1,1,1,1,1 } };
		auto res = sln.cherryPickup(grid);
		Assert(0, res);
	}

	
}

2023年1月

class Solution {
public:
int cherryPickup(vector<vector>& grid) {
m_c = grid.size();
m_preDp.assign(1, vector(1, grid[0][0]));
for (int len = 1; len <= m_c * 2 - 2; len++)
{
vector<vector> dp;
dp.assign(len + 1, vector(len + 1, -1));
for (int r1 = 0; r1 <= min(len,m_c-1); r1++)
{
for (int r2 = 0; r2 <= r1; r2++)
{
const int c1 = len - r1;
const int c2 = len - r2;
if ((c1 >= m_c) || (c2 >= m_c))
{
continue;
}
if ((grid[r1][c1] < 0) || (grid[r2][c2] < 0))
{
continue;
}
int tmp1 = grid[r1][c1];
if (r1 != r2)
{
tmp1 += grid[r2][c2];
}
int tmp2 = -1;
Test(tmp2, grid, r1, r2, len - 1);
Test(tmp2, grid, r1 - 1, r2, len - 1);
Test(tmp2, grid, r1, r2 - 1, len - 1);
Test(tmp2, grid, r1 - 1, r2 - 1, len - 1);
if (tmp2 < 0)
{
continue;
}
dp[r1][r2] = tmp1 + tmp2;
}
}
m_preDp.swap(dp);
}
return max(0,m_preDp[m_c-1][m_c-1]);
}
void Test(int& iNew,const vector<vector>& grid,int r1, int r2, int iPreLen)
{
if (r1 < 0 || r1 > iPreLen)
{
return;
}
if (r2 < 0 || r2 > iPreLen)
{
return;
}
if (r1 < r2)
{
int tmp = r1;
r1 = r2;
r2 = tmp;
}
if (m_preDp[r1][r2] < 0)
{
return;
}
iNew = max(iNew,m_preDp[r1][r2]);
}
int m_c;
vector<vector> m_preDp;
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

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

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

相关文章

Golang 搭建 WebSocket 应用(六) - 监控

我在上一篇文章中&#xff0c;提到了目前的认证方式存在一些问题&#xff0c;需要替换为一种更简单的认证方式。 但是最后发现&#xff0c;认证这个实在是没有办法简单化&#xff0c;认证本身又是另外一个不小的话题了&#xff0c;因此关于这一点先留个坑。 本文先讨论一下另外…

前端开发必备 HTML的常用标签(二)

目录 一、HTML语言 二、水平线标签 三、字体样式标签 四、注释和特殊符号 一、HTML语言 HTML&#xff08;Hypertext Markup Language&#xff09;是一种标记语言&#xff0c;用于创建网页的结构和内容。它由一系列的标签组成&#xff0c;这些标签定义了网页中各个元素的结…

商铺工厂119消防火灾SOS声光一键报警器平台联网

商铺工厂119消防火灾SOS声光一键报警器平台联网 1.设有火灾自动报警系统的建筑&#xff0c;宜选择符合相关现行国家技术标准的消防应急广播、火灾声光警报类产品&#xff0c;由火灾报警或消防联动控制器进行控制&#xff0c;在消防控制室应能一键启动全楼火灾声光警报或向全楼进…

阿里云腾讯七牛内容安全配置

一&#xff0c;阿里云 1&#xff0c;配置RAM角色权限 向RAM用户授权系统策略权限&#xff1a;AliyunYundunGreenWebFullAccess 2&#xff0c;内容安全控制台——授权访问OSS 不授权——会报错——no permission(not authorized about role AliyunCIPScanOSSRole)

Pytest插件“pytest-selenium” - 让自动化测试更简洁

在现代Web应用的开发中,自动化测试成为确保网站质量的重要手段之一。而Pytest插件 pytest-selenium 则为开发者提供了简单而强大的工具,以便于使用Python进行Web应用的自动化测试。本文将深入介绍 pytest-selenium 插件的基本用法和实际案例,助你轻松进入无忧的Web应用测试之…

LeetCode 9.回文数(python版)

需求 给你一个整数 x &#xff0c;如果 x 是一个回文整数&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。回文数是指正序&#xff08;从左向右&#xff09;和倒序&#xff08;从右向左&#xff09;读都是一样的整数。 例如&#xff0c;121 是回文&#xff0…

【惠友小课堂】正确认识「股骨头坏死」,必读!

在上一篇门诊故事中讲到的孙女士&#xff0c;一开始觉得自己腿疼的原因可能是股骨头坏死&#xff0c;结果在王教授的诊断下发现其实是髋关节发育不良&#xff0c;给出的专业建议是需要进行髋关节置换手术治疗。这恰恰反映了一个情况&#xff0c;很多病人会把“腿疼”的原因归咎…

【GitHub项目推荐--微软开源的可视化工具】【转载】

说到数据可视化&#xff0c;大家都很熟悉了&#xff0c;设计师、数据分析师、数据科学家等&#xff0c;都需要用各种方式各种途径做着数据可视化的工作.....当然许多程序员在工作中有时也需要用到一些数据可视化工具&#xff0c;如果工具用得好&#xff0c;就可以把原本枯燥凌乱…

中国电子学会2021年12月份青少年软件编程Scratch图形化等级考试试卷一级真题(含答案)

一、单选题&#xff08;共25题&#xff0c;每题2分&#xff0c;共50分&#xff09; 1.点击下列哪个按钮&#xff0c;可以让正在运行的程序停下来&#xff1f;&#xff08;&#xff09;(2分) A. B. C. D. 2.小乔完成了一个编程作品后&#xff0c;点击“文件”中的“保…

【Linux】Linux基本操作(二):rm rmdir man cp mv cat echo

承接上文&#xff1a; 【【Linux】Linux基本操作&#xff08;一&#xff09;&#xff1a;初识操作系统、ls、cd、touch、mkdir、pwd 】 目录 1.rmdir指令 && rm 指令&#xff1a; rmdir -p #当子目录被删除后如果父目录也变成空目录的话&#xff0c;就连带父目录一…

【设计模式】文件目录管理是组合模式吗?

组合模式是什么&#xff1f; 组合模式是一种将对象组合成树形结构以表示"部分-整体"的层次结构的设计模式。它使得用户对单个对象和组合对象的使用具有一致性。 组合模式在什么情况下使用&#xff1f; 当你发现你需要在代码中实现树形数据结构&#xff0c;让整体-部…

户外机器人区域覆盖算法仿真测试平台设计与实现(预告)

要求14周完成。一定要熟练掌握人工智能工具的使用。 起伏地形环境多机器人编队运动控制与路径规划研究_2016年中小结-CSDN博客 简要版本 随着机器人技术的快速发展&#xff0c;户外机器人在农业、环境监测、搜索与救援等领域的应用日益广泛。为了实现高效、准确的区域覆盖&…

基于docker创建nginx容器

docker一键安装可以参考我这个博客&#xff1a;一键安装docker 1.创建基础容器 docker run -p280:280 --name nginx -d nginx创建挂载到容器的宿主机文件夹 mkdir -p /home/000nginx-ebrms-ftp/html mkdir -p /home/000nginx-ebrms-ftp/logs mkdir -p /home/000nginx-ebrms-f…

FPGA高端项目:Xilinx Artix7 系列FPGA纯verilog图像缩放工程解决方案 提供4套工程源码和技术支持

目录 1、前言版本更新说明给读者的一封信FPGA就业高端项目培训计划免责声明 2、相关方案推荐我这里已有的FPGA图像缩放方案本方案在Xilinx Kintex7 系列FPGA上的应用本方案在国产FPGA紫光同创系列上的应用本方案在国产FPGA高云系列上的应用 3、设计思路框架设计框图视频源选择o…

vue中引入sass、scss

常规步骤 1. 创建项目 使用vue cli 脚手架工具创建项目 vue create xxxx2. 创建全局样式文件 全局样式变量 路径&#xff1a;/assets/styles/variables.scss //flex 布局变量 $--flex-direction: ("row", "column"); $--flex-position: ("start"…

如何从命令行运行testng.xml?

目录 创建一个新的java项目并从命令行运行testng.xml 使用命令行运行XML文件 从命令行运行现有maven项目的XML文件 在这篇文章中&#xff0c;我们将使用命令行运行testng.xml。有多种场景需要使用命令行工具运行testng.xml。也许您已经创建了一个maven项目&#xff0c;现在想…

2024执业医师考试报名流程及上传照片要求详解

2024年执业医师和助理医师考试的报名工作将于1月22日正式启动&#xff0c;报名截止日期为2月4日。建议考生尽早报名&#xff0c;以避免在报名截止日期临近时出现拥挤情况。您可根据本文介绍&#xff0c;提前准备好报名所需资料、证件照电子版和相关证明材料&#xff0c;并了解报…

【算法】使用优先级队列(堆)解决算法题(TopK等)(C++)

文章目录 1. 前言2. 算法题1046.最后一块石头的重量703.数据流中的第K大元素 2.5 如何选择大根堆 与 小根堆&#xff1f; 为什么选择大根堆&#xff08;小根堆&#xff09;&#xff1f;692.前K个高频单词295.数据流的中位数 1. 前言 我们知道&#xff1a;优先级队列是一种常用…

C# .NET读取Excel文件并将数据导出到DataTable、数据库及文本

Excel文件是存储表格数据的普遍格式&#xff0c;因此能够高效地读取和提取信息对于我们来说至关重要。C#语言借助.NET Framework和各种库的广泛功能&#xff0c;能够进行高效的数据操作。利用C#读取Excel文件并将数据写入数据库和DataTable&#xff0c;或者将数据用于其他目的&…

Rust基础语法1

所有权转移&#xff0c;Rust中没有垃圾收集器&#xff0c;使用所有权规则确保内存安全&#xff0c;所有权规则如下&#xff1a; 1、每个值在Rust中都有一个被称为其所有者&#xff08;owner&#xff09;的变量&#xff0c;值在任何时候只能有一个所有者。 2、当所有者离开作用域…