【图论 状态压缩 枚举】2959. 关闭分部的可行集合数目

这篇具有很好参考价值的文章主要介绍了【图论 状态压缩 枚举】2959. 关闭分部的可行集合数目。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文涉及知识点

图论 状态压缩 枚举 多源路径

LeetCode2959. 关闭分部的可行集合数目

一个公司在全国有 n 个分部,它们之间有的有道路连接。一开始,所有分部通过这些道路两两之间互相可以到达。

公司意识到在分部之间旅行花费了太多时间,所以它们决定关闭一些分部(也可能不关闭任何分部),同时保证剩下的分部之间两两互相可以到达且最远距离不超过 maxDistance 。

两个分部之间的 距离 是通过道路长度之和的 最小值 。

给你整数 n ,maxDistance 和下标从 0 开始的二维整数数组 roads ,其中 roads[i] = [ui, vi, wi] 表示一条从 ui 到 vi 长度为 wi的 无向 道路。

请你返回关闭分部的可行方案数目,满足每个方案里剩余分部之间的最远距离不超过 maxDistance。

注意,关闭一个分部后,与之相连的所有道路不可通行。

注意,两个分部之间可能会有多条道路。
示例 1:
输入:n = 3, maxDistance = 5, roads = [[0,1,2],[1,2,10],[0,2,10]]
输出:5
解释:可行的关闭分部方案有:

  • 关闭分部集合 [2] ,剩余分部为 [0,1] ,它们之间的距离为 2 。
  • 关闭分部集合 [0,1] ,剩余分部为 [2] 。
  • 关闭分部集合 [1,2] ,剩余分部为 [0] 。
  • 关闭分部集合 [0,2] ,剩余分部为 [1] 。
  • 关闭分部集合 [0,1,2] ,关闭后没有剩余分部。
    总共有 5 种可行的关闭方案。
    示例 2:
    输入:n = 3, maxDistance = 5, roads = [[0,1,20],[0,1,10],[1,2,2],[0,2,2]]
    输出:7
    解释:可行的关闭分部方案有:
  • 关闭分部集合 [] ,剩余分部为 [0,1,2] ,它们之间的最远距离为 4 。
  • 关闭分部集合 [0] ,剩余分部为 [1,2] ,它们之间的距离为 2 。
  • 关闭分部集合 [1] ,剩余分部为 [0,2] ,它们之间的距离为 2 。
  • 关闭分部集合 [0,1] ,剩余分部为 [2] 。
  • 关闭分部集合 [1,2] ,剩余分部为 [0] 。
  • 关闭分部集合 [0,2] ,剩余分部为 [1] 。
  • 关闭分部集合 [0,1,2] ,关闭后没有剩余分部。
    总共有 7 种可行的关闭方案。
    示例 3:
    输入:n = 1, maxDistance = 10, roads = []
    输出:2
    解释:可行的关闭分部方案有:
  • 关闭分部集合 [] ,剩余分部为 [0] 。
  • 关闭分部集合 [0] ,关闭后没有剩余分部。
    总共有 2 种可行的关闭方案。

提示:
1 <= n <= 10
1 <= maxDistance <= 105
0 <= roads.length <= 1000
roads[i].length == 3
0 <= ui, vi <= n - 1
ui != vi
1 <= wi <= 1000
一开始所有分部之间通过道路互相可以到达。

多源路径

枚举所有没关闭的分部,共2n种可能。
每种可能最多10个节点,利用Flod 求多源路径,时间复杂度O(nnn)。
故总时间复杂度O(2nnnn)。

代码

//多源码路径
template<class T, T INF = 1000 * 1000 * 1000>
class CFloyd
{
public:
	CFloyd(const  vector<vector<T>>& mat)
	{
		m_vMat = mat;
		const int n = mat.size();
		for (int i = 0; i < n; i++)
		{//通过i中转
			for (int i1 = 0; i1 < n; i1++)
			{
				if (INF == m_vMat[i1][i])
				{
					continue;
				}
				for (int i2 = 0; i2 < n; i2++)
				{
					//此时:m_vMat[i1][i2] 表示通过[0,i)中转的最短距离
					m_vMat[i1][i2] = min(m_vMat[i1][i2], m_vMat[i1][i] + m_vMat[i][i2]);
					//m_vMat[i1][i2] 表示通过[0,i]中转的最短距离
				}
			}
		}
	};
	vector<vector<T>> m_vMat;
};

class Solution {
public:
	int numberOfSets(int n, int maxDistance, vector<vector<int>>& roads) {
		int iRet = 0;
		for (int iMask = 0; iMask < (1 << n); iMask++)
		{
			iRet += Do(iMask, n, maxDistance, roads);
		}
		return iRet;
	}
	bool Do(int iMask, int n, int maxDistance, vector<vector<int>>& roads)
	{
		vector<vector<int>> mat(n, vector<int>(n, 1000'000'000));
		for (int i = 0; i < n; i++) {
			mat[i][i] = 0;
		}
		for (const auto& v : roads)
		{
			if ((iMask & (1 << v[0])) && (iMask & (1 << v[1]))) {
				mat[v[1]][v[0]] = mat[v[0]][v[1]] = min(mat[v[0]][v[1]], v[2]);	
			}
		}
		CFloyd<int> floyd(mat);
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++)
			{
				if ((iMask & (1 << i)) && (iMask & (1 << j)))
				{
					if (floyd.m_vMat[i][j] > maxDistance)
					{
						return false;
					}
				}
			}
		}
		return true;
	}
};

测试用例

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()
{
	int n, maxDistance;
	vector<vector<int>> roads;
	{
		n = 3, maxDistance = 12, roads = { {1, 0, 11},{1, 0, 16},{0, 2, 13} };
		auto res = Solution().numberOfSets(n, maxDistance, roads);
		Assert(5, res);
	}
	{
		n = 3, maxDistance = 5, roads = { {0,1,2},{1,2,10},{0,2,10} };
		auto res = Solution().numberOfSets(n, maxDistance, roads);
		Assert(5 , res);
	}
	
	

	//CConsole::Out(res);
}

优化了封装类

template<class T = int >
class CFloyd
{
public:
	CFloyd(int n, const T INF = 1000 * 1000 * 1000):m_INF(INF)
	{
		m_vMat.assign(n, vector<T>(n, m_INF));
		for (int i = 0; i < n; i++) {
			m_vMat[i][i] = 0;
		}
	}
	void SetEdge(int i1, int i2,const T& dis, bool bDirect = false)
	{
		m_vMat[i1][i2] = min(m_vMat[i1][i2],dis);
		if (!bDirect) {
			m_vMat[i2][i1] = m_vMat[i1][i2];
		}
	}
	vector<vector<T>> Dis()
	{
		auto vResMat = m_vMat;
		const int n = m_vMat.size();
		for (int i = 0; i < n; i++)
		{//通过i中转
			for (int i1 = 0; i1 < n; i1++)
			{
				if (m_INF == vResMat[i1][i])
				{
					continue;
				}
				for (int i2 = 0; i2 < n; i2++)
				{
					//此时:m_vMat[i1][i2] 表示通过[0,i)中转的最短距离
					vResMat[i1][i2] = min(vResMat[i1][i2], vResMat[i1][i] + vResMat[i][i2]);
					//m_vMat[i1][i2] 表示通过[0,i]中转的最短距离
				}
			}
		}
		return vResMat;
	};
	vector<vector<T>> m_vMat;//结果串
	const T m_INF;
};

class Solution {
public:
	int numberOfSets(int n, int maxDistance, vector<vector<int>>& roads) {
		int iRet = 0;
		for (int iMask = 0; iMask < (1 << n); iMask++)
		{
			iRet += Do(iMask, n, maxDistance, roads);
		}
		return iRet;
	}
	bool Do(int iMask, int n, int maxDistance, vector<vector<int>>& roads)
	{			
		CFloyd<int> floyd(n);	
		for (const auto& v : roads)
		{
			if ((iMask & (1 << v[0])) && (iMask & (1 << v[1]))) {
				floyd.SetEdge(v[0],v[1],v[2]);
			}
		}
		auto res = floyd.Dis();
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++)
			{
				if ((iMask & (1 << i)) && (iMask & (1 << j)))
				{
					if (res[i][j] > maxDistance)
					{
						return false;
					}
				}
			}
		}
		return true;
	}
};

【图论 状态压缩 枚举】2959. 关闭分部的可行集合数目,# 算法题,图论,算法,c++,力扣,枚举,状态压缩,关闭

扩展阅读

视频课程

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

【图论 状态压缩 枚举】2959. 关闭分部的可行集合数目,# 算法题,图论,算法,c++,力扣,枚举,状态压缩,关闭文章来源地址https://www.toymoban.com/news/detail-849895.html

到了这里,关于【图论 状态压缩 枚举】2959. 关闭分部的可行集合数目的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • java基础-集合+泛型+枚举

    说明: 集合框架是一个类库的集合,里面还有很多接口。 里面虚框都是接口 。 全部在java.util HashSet是基于HashMap实现的。 TreeSet是一个有序Set。 ArrayList能快速随机访问,可变大小。 LinkedList随机访问相对慢,但是可以当作stack或者queue来用。 下面是List接口常用的方法: 使用的

    2024年02月20日
    浏览(39)
  • C# 枚举和集合练习

    Lumberjack.cs类: Main方法: Card.cs类: Suits集合: Values集合: CardComparerByValue.cs Main方法: RetiredPlayer.cs类: Main方法: Breeds.cs: Dog.cs: Main方法: Duck.cs类: DuckComparer.cs DuckComparerByKind.cs DuckComparerBySize.cs Program.cs

    2024年02月09日
    浏览(41)
  • C# 错误: 集合已修改,可能无法执行枚举操作

    出错原因是使用了RemoveAt()函数移除了数据中的某一个数,导致数据发生了错位(参考链接一) 解决方案: 第一种解决方法:使用for循环 第二种解决方法:调用ToArray()方法,然后再进行foreach循环 参考链接: 链接一:[C#]集合已修改;可能无法执行枚举操作 - wolfy - 博客园 (

    2024年01月15日
    浏览(35)
  • 集合论与图论(下)

    零图: 只有点没有边的图; 重边: 两个节点不只有一条边; 线图: 没有重边; 简单图: 没有重边,没有环; 子图: 新生成的图的点和边是原来图点和边的子集,如果两个图不同就是真子图; 生成子图: 新生成的图点的个数和原来的图点的个数相同,但是边比原来的边

    2024年02月06日
    浏览(39)
  • 软考:软件工程:软件开发方法,软件可行性分析,需求分析,ER实体图,数据流图,状态转换图,数据字典

    提示:系列被面试官问的问题,我自己当时不会,所以下来自己复盘一下,认真学习和总结,以应对未来更多的可能性 关于互联网大厂的笔试面试,都是需要细心准备的 (1)自己的科研经历, 科研内容 ,学习的相关领域知识,要熟悉熟透了 (2)自己的实习经历,做了 什

    2024年02月11日
    浏览(44)
  • 【Shell 命令集合 备份压缩 】Linux 解压缩文件 unzip命令 使用指南

    Shell 命令专栏:Linux Shell 命令全解析 unzip 命令在 Linux 系统中主要用于解压 .zip 格式的压缩文件。 在这个命令中, -x 选项表示解压, -z 选项表示处理 .gz 压缩, -v 选项表示显示详细信息, -f 选项表示指定文件名。 使用unzip命令可以将压缩文件解压缩到当前目录或指定的目录

    2024年02月08日
    浏览(58)
  • 枚举类型 表示不同的 HTTP 状态码和相应的错误消息

    java web业务中经常用常量来表示不同的 HTTP 响应状态,比如 这种枚举的使用方式允许你在代码中使用这些常量来表示不同的 HTTP 响应状态,而不需要硬编码状态码和错误消息。这提高了代码的可读性和可维护性,并降低了错误的风险,因为你可以使用这些常量而不是手动输入状

    2024年02月08日
    浏览(40)
  • 蓝桥杯-回路计数(状态压缩、动态规划)

    蓝桥学院由 21 21 21 栋教学楼组成,教学楼编号 11 11 11 ​​ 到 21 21 21 ​​。对于两栋教学楼 a a a 和 b b b ​,当 a a a 和 b b b 互质时, a a a 和 b b b 之间有一条走廊直接相连,两个方向皆可通行,否则没有直接连接的走廊。 小蓝现在在第一栋教学楼,他想要访问每栋教学楼正

    2024年02月08日
    浏览(60)
  • 图论08-图的建模-状态的表达与理解 - 倒水问题为例

    从初始的 (x,y) 状态,到最后变成 (4,?) 或者 (?,4) . 本道题对于 (x,y) 的状态,可以使用 10x+y 进行表达,也就是变成了一个数字,分别放在不同的数位上。 但是本状态的表示方法不适用单个数组超过9的,因为一个数位只能表示0-9.。 涉及思想: 状态压缩 1 终止条

    2024年02月06日
    浏览(33)
  • MySQL服务关闭开机自启,改成手动启动状态

    最近在写前端,所以就先把后端数据库禁用或手动启动吧。防止浪费太多内存或资源。一般就之前损坏了的数据库就禁用吧,其他最近不常用的服务就没必要开机自启动吧,毕竟电脑只有一台,不想学习想用电脑来玩的话就讲工作服务从开机自启动状态改成手动状态吧。 首先

    2024年02月09日
    浏览(50)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包