力扣刷题之2959.关闭分部的可行集合数目

news2024/9/23 3:25:20

题干描述

一个公司在全国有 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个分部组成的图,每个分部之间有若干条道路。
  2. 我们需要计算可以关闭分部的方案数量,满足剩余分部之间的最远距离不超过maxDistance。

解题方法 

  1. 使用位掩码枚举所有可能的分部组合。
  2. 对每个组合,使用Floyd-Warshall算法计算所有节点对之间的最短路径。
  3. 验证每个组合是否满足条件:所有节点两两之间的最远距离不超过maxDistance。

代码设计 

1.初始化和输入解析

  • 动态分配opened数组,用于表示哪些分部是打开的。
  • 动态分配二维数组d,用于存储节点之间的最短距离。
int res = 0;
	int* opened = (int*)malloc(n * sizeof(int));//动态分配数组opened,用于表示那些分部是打开的
	int** d = (int**)malloc(n * sizeof(int*));//动态分配二维数组d,用于存储节点之间的最短距离
	for (int i = 0; i < n; i++)
	{
		d[i] = (int*)malloc(n * sizeof(int));
	}

 2.枚举所有可能的子集组合

  • 使用掩码mask枚举所有可能的子集组合,每个掩码表示一种组合方式。
//枚举所有可能的子集组合,使用掩码表示
	for (int mask = 0; mask < (1 << n); mask++)
	{
		//初始化opened数组,表示当前子集中那些节点是打开的
		for (int i = 0; i < n; i++)
		{
			opened[i] = mask & (1 << i);
		}
		//初始化距离矩阵d,将所有的节点对之间的距离初始化为一个很大的值(表示无穷大)
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < n; j++) {
				d[i][j] = 1000000;
			}
		}

3.更新距离矩阵

  • 根据当前子集中打开的节点,更新距离矩阵d。
  • 仅当两个节点都在当前子集中时,才更新这两个节点之间的距离。
//根据当前子集中的打开节点更新距离矩阵d
		for (int k = 0; k < roadsSize; k++)
		{
			int i = roads[k][0], j = roads[k][1], r = roads[k][2];
			if (opened[i] && opened[j]) {
				d[i][j] = d[j][i] == (d[i][j] < r) ? d[i][j] : r;
			}
		}

4. Floyd-Warshall 算法

  • 使用Floyd-Warshall 算法计算当前子集中所有节点对之间的最短距离。
  • 如果两个节点之间存在间接路径,更新它们之间的最短路径。

 

//使用Floyd-Warshall 算法计算所有节点对之间的最短路径
		for (int k = 0; k < n; k++)
		{
			if (opened[k]) {
				for (int i = 0; i < n; i++)
				{
					if (opened[i]) {
						for (int j = 0; j < n; j++)
						{
							if (opened[j]) {
								if (d[i][k] + d[k][j] < d[i][j]) {
									d[i][j] = d[i][k] + d[k][j];
								}
							}
						}
					}
				}
			}
		}
	}

5.验证子集

  • 检查当前子集中所有节点两两之间的最远距离是否不超过maxDistance。
  • 如果所有节点都满足条件,则将当前子集计入结果res。
//验证当前子集是否满足所有节点两两之间的最远距离不超过maxDistance
	int good = 1;
	for (int i = 0; i < n; i++)
	{
		if (opened[i]) {
			for (int j = i + 1; j < n; j++)
			{
				if (opened[j] && d[i][j] > maxDistance) {
					good = 0;
					break;
				}
			}
			if (!good)
			{
				break;
			}
		}
		res += good;
	}

6.释放动态内存

  • 释放之前动态分配的内存避免内存泄漏。

 

//释放动态分配的内存
	for (int i = 0; i < n; i++)
	{
		free(d[i]);
	}
	free(d);
	free(opened);
	return res;

完整的代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

int numberOfSets(int n, int maxDistance, int** roads, int roadsSize, int* roadsColSize) {
	int res = 0;
	int* opened = (int*)malloc(n * sizeof(int));//动态分配数组opened,用于表示那些分部是打开的
	int** d = (int**)malloc(n * sizeof(int*));//动态分配二维数组d,用于存储节点之间的最短距离
	for (int i = 0; i < n; i++)
	{
		d[i] = (int*)malloc(n * sizeof(int));
	}

	//枚举所有可能的子集组合,使用掩码表示
	for (int mask = 0; mask < (1 << n); mask++)
	{
		//初始化opened数组,表示当前子集中那些节点是打开的
		for (int i = 0; i < n; i++)
		{
			opened[i] = mask & (1 << i);
		}
		//初始化距离矩阵d,将所有的节点对之间的距离初始化为一个很大的值(表示无穷大)
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < n; j++) {
				d[i][j] = 1000000;
			}
		}
		//根据当前子集中的打开节点更新距离矩阵d
		for (int k = 0; k < roadsSize; k++)
		{
			int i = roads[k][0], j = roads[k][1], r = roads[k][2];
			if (opened[i] && opened[j]) {
				d[i][j] = d[j][i] == (d[i][j] < r) ? d[i][j] : r;
			}
		}

		//使用Floyd-Warshall 算法计算所有节点对之间的最短路径
		for (int k = 0; k < n; k++)
		{
			if (opened[k]) {
				for (int i = 0; i < n; i++)
				{
					if (opened[i]) {
						for (int j = 0; j < n; j++)
						{
							if (opened[j]) {
								if (d[i][k] + d[k][j] < d[i][j]) {
									d[i][j] = d[i][k] + d[k][j];
								}
							}
						}
					}
				}
			}
		}
	}
	//验证当前子集是否满足所有节点两两之间的最远距离不超过maxDistance
	int good = 1;
	for (int i = 0; i < n; i++)
	{
		if (opened[i]) {
			for (int j = i + 1; j < n; j++)
			{
				if (opened[j] && d[i][j] > maxDistance) {
					good = 0;
					break;
				}
			}
			if (!good)
			{
				break;
			}
		}
		res += good;
	}
	//释放动态分配的内存
	for (int i = 0; i < n; i++)
	{
		free(d[i]);
	}
	free(d);
	free(opened);
	return res;
}
int main() {
	int n = 3;
	int maxDistance = 5;
	int roadsSize = 3;
	int roadsColSize[] = { 3, 3, 3 };

	// 动态分配二维数组 roads,用于存储道路信息
	int** roads = (int**)malloc(roadsSize * sizeof(int*));
	for (int i = 0; i < roadsSize; i++) {
		roads[i] = (int*)malloc(3 * sizeof(int));
	}

	// 初始化道路信息
	roads[0][0] = 0; roads[0][1] = 1; roads[0][2] = 2;
	roads[1][0] = 1; roads[1][1] = 2; roads[1][2] = 10;
	roads[2][0] = 0; roads[2][1] = 2; roads[2][2] = 10;

	// 计算并输出结果
	int result = numberOfSets(n, maxDistance, roads, roadsSize, roadsColSize);
	printf("Total feasible solutions: %d\n", result);

	// 释放动态分配的内存
	for (int i = 0; i < roadsSize; i++) {
		free(roads[i]);
	}
	free(roads);

	return 0;
}

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

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

相关文章

AV1 编码标准屏幕内容编码技术概述

AV1 屏幕内容编码 为了提高屏幕捕获内容的压缩性能&#xff0c;AV1采用了几种编码工具&#xff0c;例如用于处理屏幕画面中重复模式的内帧内块复制&#xff08;IntraBC&#xff09;&#xff0c;以及用于处理颜色数量有限的屏幕块的调色板模式。 帧内块拷贝 AV1 编码中的 Intra …

【Vue】快速入门:构建你的第一个Vue 3应用

文章目录 一、Vue简介二、环境搭建1. 安装Node.js和npm2. 安装Vue CLI 三、创建Vue项目四、项目结构介绍五、组件基础创建一个组件使用组件 六、模板语法插值指令v-bindv-ifv-for 七、事件处理八、状态管理安装Vuex创建Store使用Store 九、路由基础安装Vue Router配置路由使用路…

FFmpeg播放视频

VS2017+FFmpeg6.2.r113110+SDL2.30.5 1.下载 ShiftMediaProject/FFmpeg 2.下载SDL2 3.新建VC++控制台应用 3.配置include和lib 4.把FFmpeg和SDL的dll 复制到工程Debug目录下,并设置调试命令

24年Hvv准备,6大方向,33篇技战法

进去不少小伙伴后台留言说需要技战法&#xff0c;因此小编对市面上的技战法进行了收集和总结&#xff0c;并对收集来的技战法进行了分类&#xff0c;总共分了6大类&#xff0c;共计33篇&#xff1a; 有需要的小伙伴关注我&#xff0c;点击在看&#xff0c;并私信回复“技战法”…

IO、进程、线程03

第一题&#xff1a;预习 opendir 和 readdir函数 opendir 和 readdir 是两个在C语言&#xff08;特别是使用POSIX标准的系统&#xff0c;如Linux和UNIX&#xff09;中用于目录遍历的函数。这两个函数属于标准的C库中的目录操作部分&#xff0c;通常与<dirent.h>头文件一…

MySQL学习记录 —— 이십일 MySQL服务器文件系统(1)

文章目录 1、配置和默认值2、系统变量和选项1、介绍2、常用选项3、如何使用系统变量 3、常用服务器配置4、查看状态变量5、MySQL数据目录 mysql的服务端就是mysqld&#xff0c;d就是daemon&#xff0c;守护进程的意思。 配置文件中[mysqld]部分时服务器支持的启动选项。服务器…

某航空制造业集团IT信息化总体规划方案

获取完整方案见下图 更多有关华为研发管理/IPD、MBSE、PLM、ERP、MES、数据治理、数字样机等方面免费解决方案、资料获取&#xff0c;请见下图

开放式耳机哪个品牌好?开放式耳机实用推荐

开放式耳机是一种耳机类型&#xff0c;其外壳是开放的&#xff0c;发声单元的背面和外界相通。这种耳机的外壳上通常有许多小孔或者直接能够看到内部的发声单元。 而且开放式耳机几乎摒弃了传统耳机几乎所有缺点&#xff01;&#xff01; ❌有线耳机&#xff1a;运动的时候特别…

如何走出低能量状态?

晚上好。 每个人都难免会有状态不佳的时候。可能是遭受压力&#xff0c;可能是事情不顺&#xff0c;也可能无缘无故、突然就陷入情绪的低谷之中。 这时&#xff0c;我们很容易感到精力不济&#xff0c;无精打采&#xff0c;明明有许多事情要做和想做&#xff0c;但总是提不起精…

宠物空气净化器哪款品牌好?口碑好的猫用空气净化器排名

猫咪每年掉毛两次&#xff0c;一次掉半年的现象真让人头疼。作为一位5年资深铲屎官&#xff0c;特别是在掉毛季节&#xff0c;猫毛无处不在&#xff0c;对此深有体会。宠物空气净化器已成为铲屎官们的救星&#xff0c;能迅速清理家中的宠物毛发和异味&#xff0c;是养猫家庭的必…

RK3568平台(环境篇)windon与ubuntu之间文件互传

一.windon与ubuntu共享文件夹 打开设置&#xff1a; 点击选项&#xff0c;共享文件夹 共享文件夹&#xff0c;就是在电脑的固定盘符下面&#xff0c;找一个文件夹为Windows和Linux都能看得见的共用的看得见的文件夹&#xff0c;点击添加文件夹。 点击确定后在ubuntu添加共享文…

python 获取Shopee虾皮商家店铺商品列表 虾皮api数据采集

此api接口可用于获取虾皮平台商家店铺的商品列表&#xff0c;目前land参数支持id、vn、my、th、sg、ph、tw&#xff08;印尼、越南、马来、泰国、新加坡、菲律宾、台湾&#xff09;。 若有需要&#xff0c;请点击文末链接联系我们。 详细采集页面如下https://shopee.tw/yuesh…

【快速逆向一/无过程/有源码】《大学》在线投稿系统

逆向日期&#xff1a;2024.07.18 使用工具&#xff1a;Node.js 加密工具&#xff1a;Crypto-js标准库 文章全程已做去敏处理&#xff01;&#xff01;&#xff01; 【需要做的可联系我】 【点赞 收藏 关注 】仅供学习&#xff0c;仅供学习&#xff0c; 本文为快速逆向&#x…

IC测试:Shmooing, Shmoo测试, Shmoo图

Shmoo测试/Shmooing 在半导体测试中&#xff0c;Shmooing是一种测试技术&#xff0c;通过扫描一个范围内的测试条件参数来查看正在运行的被测器件&#xff0c;就像它在现实世界中的表现一样。 测试的参数类型取决于IC的目的和类型以及环境。至少绘制了两个参数。&#xff08;…

鸿蒙仓颉语言【基础-数据类型dataType】

数据类型 仓颉编程&#xff08;CangjieLang&#xff09;是强类型语言,变量和函数参数都需要显式声明类型&#xff0c;例如&#xff1a; public let growable: Bool false public func get(value: Array<Byte>): Int64。基础数据类型 仓颉&#xff08;CangjieLang&…

生命周期的妙用——Vue3

Vue3的生命周期 从Vue2到Vue3&#x1f47e;不只onMounted又见keep-alive主要属性被你包裹应用场景 ) 从Vue2到Vue3&#x1f47e; Vue 3 保留了大多数 Vue 2 的生命周期钩子&#xff0c;同时引入了组合 API 中的生命周期钩子。以下是 Vue 3 中的生命周期钩子&#xff1a; 不…

R语言进行集成学习算法:随机森林

# 10.4 集成学习及随机森林 # 导入car数据集 car <- read.table("data/car.data",sep ",") # 对变量重命名 colnames(car) <- c("buy","main","doors","capacity","lug_boot","safety"…

linux下JDK的安装

前言&#xff1a; 安装部署java开发的代码都需要java环境&#xff0c;这里记录下linux下JDK的安装过程&#xff0c;仅供学习参考。 JDK的下载 下载地址&#xff1a;https://www.oracle.com/java/technologies/downloads 选择和操作系统匹配的版本进行下载 查看操作系统&…

记录些MySQL题集(11)

MySQL 组提交原理 MySQL 中事务的两阶段提交保证了 redo log 与 binlog 两种日志文件的数据一致性&#xff0c;但是并发事务场景下还需要保证事务顺序的一致性&#xff0c;因此通过组提交机制在保证顺序一致性的前提下提高写入效率。因此组提交是两阶段提交的一部分。 两阶段…

JavaScript基础(十五)

变量&返回值 js中的变量有两种: 局部变量和全局变量 全局变量: 在函数外声明的变量&#xff0c;网页上的所有函数和脚本都能访问它。 局部变量&#xff1a; 在函数内部声明的变量&#xff08;必须使用var&#xff09;&#xff0c;只能在函数内部访问它&#xff0c;我们…