我的PAT-ADVANCED代码仓:https://github.com/617076674/PAT-ADVANCED
原题链接:https://pintia.cn/problem-sets/994805342720868352/problems/994805396953219072
题目描述:
题目翻译:
1072 加油站
加油站的位置选取,应该使得其与任何住宅之间的最小距离尽可能远。同时又必须保证所有的居民都在自己的服务范围内。
现在给你一张城市的地图和几个加油站的候选位置,你需要给出最好的建议。如果有超过1种方案,选取离所有住宅平均距离最小的方案。如果方案还不唯一,输出编号最小的加油站位置。
输入格式:
每个输入文件包含一个测试用例。在每个测试用例中,第一行给出4个正整数:N(<= 1000),代表房子数量;M(<= 10),代表加油站的候选位置总数;K(<= 10000),代表连接加油站和房子的道路数目;Ds,代表加油站的最大服务距离。所有房子的编号为1 ~ N。所有加油站的候选位置编号从G1 ~ GM。
接下来的K行,每行以下述形式描述一条道路:
P1 P2 Dist
P1和P2代表道路的两端点,两端点均既有可能是房子编号也有可能是加油站的候选位置编号,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
知识点:Dijkstra算法、Bellman-Ford算法、SPFA算法
思路一:Dijkstra算法(邻接表实现)
首先是输入的节点标号与加油站编号全部要转换成数字编号。我假设房子的编号为1 ~ N,加油站的编号为N + 1 ~ N + M。由于输入的道路两端有可能是数字也有可能是G开头的字符串,我们统一用字符串接收,并设置一个函数change()将接收的字符串转换为数字编号。
我的转换规则是对G开头的字符串,取其后面一个字符与字符'0'作差,再返回N + 差值。但是这样做忽略了G10的情况,因此,当G开头的字符串长度是3位时,我们需要返回N + 10。
而我一开始所犯的错误是,忽略了N的范围,N最大可以到达1000。所以这个编号不止有一个字符,我一开始只考虑了N是个位数的情况。因此我们需要用头文件<sstream>中的stringstream类型将数字字符串转换成数字。
对每个加油站都用Dijkstra算法求其到各个房子的最小距离。
对每个加油站点,首先判断其到每个房子的最小距离是否小于等于Ds,如果有任何一个值大于Ds,这个加油站点是不可取的。
其次,对可取的加油站点进行筛选。
(1)筛选条件一:与任何住宅之间的最小距离尽可能远。
(2)筛选条件二:选取离所有住宅平均距离最小的方案。由于住宅总量一定,因此只需选取离所有住宅总距离最小的方案即可。
(3)筛选条件三:输出编号最小的加油站位置。这个条件很容易满足,我们只需要按编号从小到大遍历即可,对于住宅总距离相等的后续方案不考虑。
注意,在发现离住宅更远的最小距离后,我们不仅要更新离住宅更远的最小距离值,还需要更新离所有住宅的总距离。
结果需要