【深度优先搜索】【图论】【树】2646. 最小化旅行的价格总和

这篇具有很好参考价值的文章主要介绍了【深度优先搜索】【图论】【树】2646. 最小化旅行的价格总和。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

作者推荐

【数位dp】【动态规划】【状态压缩】【推荐】1012. 至少有 1 位重复的数字

涉及知识点

深度优先搜索 图论 树

LeetCode2646. 最小化旅行的价格总和

现有一棵无向、无根的树,树中有 n 个节点,按从 0 到 n - 1 编号。给你一个整数 n 和一个长度为 n - 1 的二维整数数组 edges ,其中 edges[i] = [ai, bi] 表示树中节点 ai 和 bi 之间存在一条边。
每个节点都关联一个价格。给你一个整数数组 price ,其中 price[i] 是第 i 个节点的价格。
给定路径的 价格总和 是该路径上所有节点的价格之和。
另给你一个二维整数数组 trips ,其中 trips[i] = [starti, endi] 表示您从节点 starti 开始第 i 次旅行,并通过任何你喜欢的路径前往节点 endi 。
在执行第一次旅行之前,你可以选择一些 非相邻节点 并将价格减半。
返回执行所有旅行的最小价格总和。
示例 1:
输入:n = 4, edges = [[0,1],[1,2],[1,3]], price = [2,2,10,6], trips = [[0,3],[2,1],[2,3]]
输出:23
解释:
上图表示将节点 2 视为根之后的树结构。第一个图表示初始树,第二个图表示选择节点 0 、2 和 3 并使其价格减半后的树。
第 1 次旅行,选择路径 [0,1,3] 。路径的价格总和为 1 + 2 + 3 = 6 。
第 2 次旅行,选择路径 [2,1] 。路径的价格总和为 2 + 5 = 7 。
第 3 次旅行,选择路径 [2,1,3] 。路径的价格总和为 5 + 2 + 3 = 10 。
所有旅行的价格总和为 6 + 7 + 10 = 23 。可以证明,23 是可以实现的最小答案。
示例 2:
输入:n = 2, edges = [[0,1]], price = [2,2], trips = [[0,0]]
输出:1
解释:
上图表示将节点 0 视为根之后的树结构。第一个图表示初始树,第二个图表示选择节点 0 并使其价格减半后的树。
第 1 次旅行,选择路径 [0] 。路径的价格总和为 1 。
所有旅行的价格总和为 1 。可以证明,1 是可以实现的最小答案。
提示:
1 <= n <= 50
edges.length == n - 1
0 <= ai, bi <= n - 1
edges 表示一棵有效的树
price.length == n
price[i] 是一个偶数
1 <= price[i] <= 1000
1 <= trips.length <= 100
0 <= starti, endi <= n - 1

【深度优先搜索】【图论】【树】2646. 最小化旅行的价格总和,# 算法题,深度优先,图论,算法,c++,LeetCode,旅行,最小

两次深度优先搜索

深度优先搜索计算进过各节点多少次

以任何一个节点(比如:0)为整课树的节点,有如下性质:
性质一:路径一定是:起点 → \rightarrow 公共祖先 → \rightarrow 终点 特例是:起点或终点就是公共祖先。
性质二:如果某棵子树包括某次旅行的起点或终点,则此次旅行必定经过此子树根节点。如果起点和终点都是此子树的节点,也算。 之后就不算了。
如何判断 节点是否属于子树:
DFS 的开始,给节点编号(访问编号)m_vTime[cur],从1到大。没有访问就是默认值0。
DFS结束时,访问编号大于等于m_vTime[cur],是本子树的节点。
m_vNeedVis 记录各节点访问的需要访问的次数。
m_vHasDo 记录那些旅行的公共祖先已经访问。

深度优先搜索枚举半价

{ 子节点节点全价 根节点半价 m i n ( 子节点节点全价,子节点节点半价 ) 根节点全价 \begin{cases} 子节点节点全价 & 根节点半价 \\ min(子节点节点全价,子节点节点半价) & 根节点全价 \\ \end{cases} {子节点节点全价min(子节点节点全价,子节点节点半价)根节点半价根节点全价
DFS2返回值两个:
一,全价、半价的较小值。
二,全价的最小值。

代码

核心代码

class CNeiBo2
{
public:
	CNeiBo2(int n, bool bDirect, int iBase = 0) :m_iN(n), m_bDirect(bDirect), m_iBase(iBase)
	{
		m_vNeiB.resize(n);
	}
	CNeiBo2(int n, vector<vector<int>>& edges, bool bDirect, int iBase = 0) :m_iN(n), m_bDirect(bDirect), m_iBase(iBase)
	{
		m_vNeiB.resize(n);
		for (const auto& v : edges)
		{
			m_vNeiB[v[0] - iBase].emplace_back(v[1] - iBase);
			if (!bDirect)
			{
				m_vNeiB[v[1] - iBase].emplace_back(v[0] - iBase);
			}
		}
	}
	inline void Add(int iNode1, int iNode2)
	{
		iNode1 -= m_iBase;
		iNode2 -= m_iBase;
		m_vNeiB[iNode1].emplace_back(iNode2);
		if (!m_bDirect)
		{
			m_vNeiB[iNode2].emplace_back(iNode1);
		}
	}
	const int m_iN;
	const bool m_bDirect;
	const int m_iBase;
	vector<vector<int>> m_vNeiB;
};

class Solution {
public:
	int minimumTotalPrice(int n, vector<vector<int>>& edges, vector<int>& price, vector<vector<int>>& trips) {
		CNeiBo2 neiBo(n, edges, false);
		m_vNeedVis.resize(n);
		m_vHasDo.resize(trips.size());
		m_vTime.resize(n);
		m_trips = trips;
		m_price = price;
		DFS(neiBo.m_vNeiB, 0, -1);
		return DFS2(neiBo.m_vNeiB, 0, -1).first;
	}
	void DFS(vector<vector<int>>& neiBo, int cur, int par)
	{
		m_vTime[cur] = ++m_llTime;
		for (const auto& next : neiBo[cur])
		{
			if (next == par)
			{
				continue;
			}
			DFS(neiBo, next, cur);
		}
		for (int i = m_trips.size()-1 ; i >=0 ; i--)
		{
			if (m_vHasDo[i])
			{
				continue;
			}
			const auto& v = m_trips[i];
			if ((m_vTime[v[0]] >= m_vTime[cur]) || (m_vTime[v[1]] >= m_vTime[cur]))
			{
				m_vNeedVis[cur]++;
				if ((m_vTime[v[0]] >= m_vTime[cur]) && (m_vTime[v[1]] >= m_vTime[cur]))
				{ 
					m_vHasDo[i] = true;
				}
			}
		}
	}
	pair<int,int> DFS2(vector<vector<int>>& neiBo, int cur, int par)
	{
		int  i2 = m_price[cur]*m_vNeedVis[cur],i1 =i2/2;
		for (const auto& next : neiBo[cur])
		{
			if (next == par)
			{
				continue;
			}
			auto [i11,i21] = DFS2(neiBo, next, cur);
			i1 += i21;
			i2 += i11;
		}
		return make_pair(min(i1, i2), i2);
	}
	vector<int> m_vNeedVis,m_vTime;// 记录各节点访问的需要访问的次数。
	vector<bool>	m_vHasDo;// 记录那些旅行的公共祖先已经访问。
	int m_llTime = 0;
	vector<vector<int>> m_trips;
	vector<int> m_price;
};

测试用例


template<class T,class T2>
void Assert(const T& t1, const T2& 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()
{	
	int n;
	vector<int>  price;
	vector<vector<int>> edges, trips;
	{
		Solution sln;
		n = 4, edges = { {0,1},{1,2},{1,3} }, price = { 2,2,10,6 }, trips = { {0,3},{2,1},{2,3} };
		auto res = sln.minimumTotalPrice(n, edges, price, trips);
		Assert(res,23);
	}

	{
		Solution sln;
		n = 2, edges = { {0,1} }, price = { 2,2 }, trips = { {0,0} };
		auto res = sln.minimumTotalPrice(n, edges, price, trips);
		Assert(res, 1);
	}
	{
		Solution sln;
		n = 5, edges = { {1,2},{2,0},{0,3},{3,4} }, price = { 12,26,22,12,2 };
		trips = { {3,3},{3,2},{3,0},{3,4},{1,1},{2,2},{4,0},{0,2},{2,3},{2,1},{4,2},{0,1},{4,2},{0,4},{0,3},{4,0},{4,0},{3,3},{4,3},{2,2},{4,2},{1,4},{3,2},{4,4},{4,2},{2,3},{4,3},{4,4},{4,2},{0,4},{4,2},{3,4},{4,0},{3,2},{3,1},{2,0},{0,4},{3,4},{2,0},{1,4},{4,2},{4,4},{2,1},{0,1},{4,1},{3,4},{0,4},{2,0},{2,0},{3,3},{4,4},{0,1},{0,1},{0,1},{2,0},{0,1},{3,1},{3,4},{3,4},{4,2},{0,4},{4,4},{3,2},{2,1},{3,2},{1,4},{1,0},{4,2},{4,3},{3,1},{4,4},{3,1},{1,0},{0,0},{0,0},{3,0},{0,2},{2,2},{3,3},{0,3} };;
		auto res = sln.minimumTotalPrice(n, edges, price, trips);
		Assert(res, 2037);
	}
	
}

2023年3月

class CNeiBo2
{
public:
CNeiBo2(int n, vector<vector>& edges, bool bDirect)
{
m_vNeiB.resize(n);
for (const auto& v : edges)
{
m_vNeiB[v[0]].emplace_back(v[1]);
if (!bDirect)
{
m_vNeiB[v[1]].emplace_back(v[0]);
}
}
}
vector<vector> m_vNeiB;
};
class Solution {
public:
int minimumTotalPrice(int n, vector<vector>& edges, vector& price, vector<vector>& trips) {
m_vParent.resize(n);
CNeiBo2 neBo(n, edges, false);
dfs(0, -1, neBo.m_vNeiB);
vector vTotalPrice(n);
for (const vector& trip : trips)
{
const auto& v0 = m_vParent[trip[0]];
const auto& v1 = m_vParent[trip[1]];
int i = 0;
for (; (i < min(v0.size(), v1.size())) && (v0[i] == v1[i]); i++);
vTotalPrice[v0[i - 1]] += price[v0[i - 1]];
for (int j = i; j < v0.size(); j++)
{
vTotalPrice[v0[j]] += price[v0[j]];
}
for (int j = i; j < v1.size(); j++)
{
vTotalPrice[v1[j]] += price[v1[j]];
}
}
int iRet = std::accumulate(vTotalPrice.begin(), vTotalPrice.end(), 0);
return iRet - MaxDFS(0, -1, neBo.m_vNeiB, vTotalPrice, true);
}
void dfs(int iCur, int iParent, const vector<vector>& vNeiBo)
{
if (-1 != iParent)
{
m_vParent[iCur] = m_vParent[iParent];
}
m_vParent[iCur].emplace_back(iCur);
for (const auto& next : vNeiBo[iCur])
{
if (iParent == next)
{
continue;
}
dfs(next, iCur, vNeiBo);
}
}
int MaxDFS(int iCur, int iParent, const vector<vector>& vNeiBo, const vector& vTotalPrice,bool bCanRoot)
{
int iRet = 0;
for (const auto& next : vNeiBo[iCur])
{
if (iParent == next)
{
continue;
}
iRet += MaxDFS(next, iCur, vNeiBo, vTotalPrice,true);
}
if ((!bCanRoot) || (0 == vTotalPrice[iCur]))
{
return iRet;
}
int iRet2 = vTotalPrice[iCur] / 2;
for (const auto& next : vNeiBo[iCur])
{
if (iParent == next)
{
continue;
}
iRet2 += MaxDFS(next, iCur, vNeiBo, vTotalPrice, false);
}
return max(iRet, iRet2);
}
vector<vector> m_vParent;
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步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++**实现。

【深度优先搜索】【图论】【树】2646. 最小化旅行的价格总和,# 算法题,深度优先,图论,算法,c++,LeetCode,旅行,最小文章来源地址https://www.toymoban.com/news/detail-827026.html

到了这里,关于【深度优先搜索】【图论】【树】2646. 最小化旅行的价格总和的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • QT最小化程序到托盘运行

    实现程序关闭时最小化托盘的功能 托盘实现显示主页面和退出的功能 支持扩展,直接引用TrayIcon类即可,对外暴露接口 单例实现,可复用 注:博主所有资源永久免费,若有帮助,请点赞转发是对我莫大的帮助 注:博主本人学习过程的分享,引用他人的文章皆会标注原作者

    2024年02月05日
    浏览(35)
  • 捕获最小化窗口的缩略图画面

    : capture minimized window window thumbnail IsIconic  最小化的窗口,API GetClientRect 返回的窗口尺寸是0x0,故无法通过GetDC+BitBlt捕获到窗口画面。 但是 Agora/zoom/tencentMeeting 都可以拿到最小化窗口的缩略图。经确认这个程序并没有注入任何dll到目标窗口,且也没有临时显示最小化了

    2024年02月07日
    浏览(31)
  • Qt实现最小化窗口到托盘图标

    目录 前言: 1.先看效果图 2.大致思路以及实现流程 3.具体代码以及解释 4.总结 使用QT开发桌面软件,将软件最小化至托盘这样的功能的是比较常见的,今天自己实现一下这个功能,并进行记录总结。  主要功能就是当软件开始运行, 在系统托盘会自动出现一个关于本软件的

    2023年04月08日
    浏览(28)
  • LabVIEW开发最小化5G系统测试平台

    LabVIEW开发最小化5G系统测试平台 由于具有大量存储能力和数据的应用程序的智能手机的激增,当前一代产品被迫提高其吞吐效率。正交频分复用由于其卓越的品质,如单抽头均衡和具有成本效益的实施,现在被广泛用作物理层技术。这些好处是以严格的同步、正交性和高功耗

    2024年02月12日
    浏览(25)
  • 最小化安装Linux系统初始化脚本

    目录 最小化安装Linux系统初始化脚本 注:此脚本适用于centos 7/8、Ubuntu1804,具体需要根据实际情况进行测试调整。 此脚本包含的功能: 允许 root 用户使用 ssh 登录 关闭 selinux 关闭防火墙 设置 ps1 设置默认编辑器为 vim 自定义 vim 自定义历史命令 修改内核参数 设置资源限制 修

    2024年02月12日
    浏览(28)
  • unity发布设置(最小化、置顶、限制单开)

    1. 勾上下图标红处,发布后可防止按windows键缩小  2.发布后程序默认最小化 3.发布的程序只能开一个进程

    2024年02月12日
    浏览(31)
  • leetcode 2616. 最小化数对的最大差值

    在数组nums中找到p个数对,使差值绝对值的和最小。 思路: 最小差值应该是数值相近的一对数之间产生,让数值相近的数字尽量靠在一起方便计算,所以需要排序。 这里不去直接考虑一对对的数字,而是直接考虑差值的取值。 用binary search搜索一个差值。 左边界是0,右边界

    2024年02月13日
    浏览(25)
  • mac 最小化全部程序回到桌面(基于alfred workflow)

    换到 mac 系统之后,很多快捷键根本就不好用,组合太多了,除了 cmd + Q/W/A/S/X/R/Z/C/V ,个人认为其它的真的一坨屎。像我的需求就是,开的窗口太多了,我需要全部最小化,再重新打开我需要那个窗口。而 Windows 上的 win + D 就是很符合我的需求,于是我研究一下 mac 怎么实现

    2024年04月17日
    浏览(31)
  • debian12 最小化安装桌面 i3wm

    怕记不住,先临时记录一下,还未整理,先凑合着看 debian12 最小安装 i3wm 一、先安装 debian12 最小安装 软件包只选择最后的两个 SSH服务,和管理工具 安装后查看IP,并用另一台电脑 ssh 连接操作,这样比较方便 ip address 更新为国内源,并更新系统 apt update apt upgrade -y 二、安装

    2024年02月04日
    浏览(30)
  • C# 实现winform软件最小化到系统托盘,开机自启动

      问题描述   用户的电脑是win7系统,应用系统在用户电脑上运行时部分功能需要访问注册表,但是使用这些功能时会提示用户没有权限访问注册表。 原因分析   win7及后续高版本系统对用户的权限控制比较严,就算用户的权限较高,但用户启动程序时默认还是以普通用

    2024年02月03日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包