当前位置: 首页 > backend >正文

每日一题(9) 垃圾箱分布

大家倒垃圾的时候,都希望垃圾箱距离自己比较近,但是谁都不愿意守着垃圾箱住。所以垃圾箱的位置必须选在到所有居民点的最短距离最长的地方,同时还要保证每个居民点都在距离它一个不太远的范围内。

现给定一个居民区的地图,以及若干垃圾箱的候选地点,请你推荐最合适的地点。如果解不唯一,则输出到所有居民点的平均距离最短的那个解。如果这样的解还是不唯一,则输出编号最小的地点。

输入格式:

输入第一行给出4个正整数:N(≤103)是居民点的个数;M(≤10)是垃圾箱候选地点的个数;K(≤104)是居民点和垃圾箱候选地点之间的道路的条数;DS​是居民点与垃圾箱之间不能超过的最大距离。所有的居民点从1到N编号,所有的垃圾箱候选地点从G1到GM编号。

随后K行,每行按下列格式描述一条道路:

P1 P2 Dist

其中P1P2是道路两端点的编号,端点可以是居民点,也可以是垃圾箱候选点。Dist是道路的长度,是一个正整数。

输出格式:

首先在第一行输出最佳候选地点的编号。然后在第二行输出该地点到所有居民点的最小距离和平均距离。数字间以空格分隔,保留小数点后1位。如果解不存在,则输出No Solution

输入样例1:

4 3 11 5
1 2 2
1 4 2
1 G1 4
1 G2 3
2 3 2
2 G2 1
3 4 2
3 G3 2
4 G1 3
G2 G1 1
G3 G2 2

输出样例1:

G1
2.0 3.3

输入样例2:

2 1 2 10
1 G1 9
2 G1 20

输出样例2:

No Solution

 

问题分析

这个问题可以分成几个步骤来解决:

  1. 构建图:根据输入的道路信息,构建一个包含所有居民点和垃圾箱候选点的无向图。
  1. 计算最短路径:使用Floyd-Warshall算法计算图中任意两点之间的最短路径。
  1. 评估候选点:对每个垃圾箱候选点,评估它到所有居民点的最短距离的最大值和平均值。
  1. 选择最佳点:根据题目要求的排序规则选择最佳的垃圾箱位置。

解题思路

Floyd-Warshall算法

Floyd-Warshall算法是一种求解多源点间最短路径的动态规划算法。时间复杂度为O(V³),其中V是图中顶点的数量。

步骤如下:

  1. 初始化距离矩阵,对于直接相连的两点,距离为道路长度;对于不直接相连的两点,距离为无穷大。
  2. 对于每个顶点k,更新任意两点i和j之间的最短路径:
   dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j])

评估候选点

对每个垃圾箱候选点G,我们需要计算:

  1. 它到所有居民点的最短距离的最大值,记为minDist
  2. 它到所有居民点的平均距离,记为avgDist
  3. 检查是否有居民点到达不了或距离超过最大允许距离DS

选择最佳点

根据题目要求,我们按照以下规则排序候选点:

  1. minDist越大越好,从所有最短距离中选最大的那个(即题目中没人想和垃圾箱做邻居)
  2. 如果minDist相同,avgDist越小越好(平均距离短为佳)
  3. 如果minDist和avgDist都相同,编号越小越好

代码实现

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;public class Main {public static void main(String[] args) throws IOException {BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));String[] s = bf.readLine().split(" ");int n = Integer.parseInt(s[0]);  // 居民点个数int m = Integer.parseInt(s[1]);  // 垃圾箱候选点个数int k = Integer.parseInt(s[2]);  // 道路条数int maxDist = Integer.parseInt(s[3]);  // 最大允许距离DSint[][] grid = new int[n + m + 1][n + m + 1];for (int i = 0; i < n + m + 1; i++) {Arrays.fill(grid[i], 999999999);  // 初始化为无穷大grid[i][i] = 0;  // 自己到自己的距离为0}// 构建图for (int i = 0; i < k; i++) {s = bf.readLine().split(" ");if (s[0].contains("G")) {// 垃圾桶编号顺延s[0] = String.valueOf(Integer.parseInt(s[0].substring(1)) + n);}if (s[1].contains("G")) {// 垃圾桶编号顺延s[1] = String.valueOf(Integer.parseInt(s[1].substring(1)) + n);}grid[Integer.parseInt(s[0])][Integer.parseInt(s[1])] = Integer.parseInt(s[2]);grid[Integer.parseInt(s[1])][Integer.parseInt(s[0])] = Integer.parseInt(s[2]);}int[][] dp = Arrays.copyOf(grid, n + m + 1);// Floyd算法计算最短路径for (int l = 1; l <= n + m; l++) {for (int i = 1; i <= n + m; i++) {for (int j = 1; j <= n + m; j++) {dp[i][j] = Math.min(dp[i][l] + dp[l][j], dp[i][j]);}}}Map<String, double[]> res = new HashMap<>();// 计算每个候选点的最小距离和平均距离for (int i = n + 1; i < n + m + 1; i++) {double min = Integer.MAX_VALUE;double sum = 0;boolean valid = true;for (int j = 1; j <= n; j++) {if (dp[i][j] == 999999999 || dp[i][j] > maxDist) {valid = false;break;}sum += dp[i][j];if (dp[i][j] < min && dp[i][j] != 0) min = dp[i][j];}if (valid) {res.put("G" + (i - n), new double[]{min, sum / n});}}// 排序选择最佳候选点List<Map.Entry<String, double[]>> sortList = new ArrayList<>(res.entrySet());Collections.sort(sortList, new Comparator<Map.Entry<String, double[]>>() {@Overridepublic int compare(Map.Entry<String, double[]> o1, Map.Entry<String, double[]> o2) {// 在这些最短距离中选择较大的排在前面if (o1.getValue()[0] < o2.getValue()[0]) {return 1;} else if (o1.getValue()[0] > o2.getValue()[0]) {return -1;} else {// 平均距离选最小if (o1.getValue()[1] < o2.getValue()[1]) {return -1;} else if (o1.getValue()[1] > o2.getValue()[1]) {return 1;} else {return o1.getKey().compareTo(o2.getKey());}}}});if (res.isEmpty()) System.out.println("No Solution");else {System.out.println(sortList.get(0).getKey());double[] val = sortList.get(0).getValue();System.out.printf("%.1f %.1f", val[0], val[1]);}}
}

 

代码解析

  1. 构建图:
  • 创建一个大小为(n+m+1)×(n+m+1)的矩阵grid,表示图中任意两点间的直接距离
  • 对于不直接相连的点,距离初始化为一个很大的数(这里是999999999)
  • 对于每条输入的道路,更新对应点对的距离
  1. 处理垃圾箱编号:
  • 为了处理方便,我们将垃圾箱候选点的编号从G1-GM映射为n+1到n+m
  • 在读入道路信息时,检查点的编号是否包含"G",如果包含则转换为相应的数字编号
  1. Floyd-Warshall算法:
  • 复制grid矩阵到dp矩阵
  • 使用三重循环实现Floyd-Warshall算法,计算任意两点间的最短路径
  1. 评估候选点:
  • 对每个垃圾箱候选点,计算它到所有居民点的最短距离的最小值(min)和平均值(sum/n)
  • 如果有任何居民点无法到达或距离超过最大允许距离,则该候选点无效
  1. 选择最佳点:
  • 将有效的候选点及其评估结果放入res映射中
  • 根据题目要求的排序规则对候选点进行排序
  • 输出排序后的第一个候选点作为最佳选择

 

http://www.xdnf.cn/news/1050.html

相关文章:

  • 基于SpinrgBoot+Vue的智慧农业管理平台-031
  • 远程医疗系统如何有效防护CC攻击
  • 智慧教室电子班牌-智能管理系统源码,‌后端‌基于Spring Boot框架,前端‌使用Vue.js框架进行组件化开发
  • 在python中装饰器的使用
  • File工具总结
  • 悟空黑桃A邀请码(31187835)
  • VSCode远程图形化GDB
  • 算法 | 鲸鱼优化算法(WOA)与强化学习的结合研究
  • Dify-web开发思路
  • Pikachu靶场-SQL注入
  • STM32——相关软件安装
  • 【Linux】:HTTPS协议
  • 相机标定(输出相机内参和畸变参数)
  • ASP.NET 中防止用户多次登录的方法
  • wkhtmltopdf - HTML转PDF/图像命令行工具
  • python@staticmethod 是什么含义?
  • Coze平台​ 创建AI智能体的详细步骤指南
  • 多源异构网络安全数据(CAPEC、CPE、CVE、CVSS、CWE、ATTCK、D3FEND)的详细解析,包括其作用、数据内容及相互联系
  • 跨越1640年的诗路对话:谢灵运与瓯江山水的古今交响
  • EasyCVR视频汇聚平台安防监控问题排查:GB28181协议摄像头不在线的排查步骤
  • 基于Spring Boot实现文件秒传的完整方案
  • 5565反射内存网络产品
  • 【数据结构_11】二叉树(5)
  • JVM面试题学习
  • 算法复杂度
  • Oracle RMAN同步数据库Active database duplicate
  • ORION:通过视觉-语言指令动作生成的一个整体端到端自动驾驶框架
  • 操作系统线程入门
  • 前端中的浮动、定位与布局
  • 使用纯前端技术html+css+js实现一个蔬果商城的前端模板!