题目
题目大意
给出房屋数目n,候选加油站的个数m,路的数目k,最大服务范围k。要求从m个站点中选出最佳站点,使得该站点到居民房屋的最短距离尽可能大,但是也不能超过最大服务范围,否则无法提供服务。如果有多个满足条件的节点,按照 最短距离 > 到各个房屋的平均距离 > 站点id 的优先级,输出第一个站点,即为最佳站点。还要输出该站点到房屋的最短距离和平均距离。如果res中没有元素,输出“No Solution”。
思路
房屋的标号从1到n,而候选加油站的标号是从G1到Gm,可以将加油站节点放在房屋节点的后面,建立一个map映射,从名字G1映射到标号n + 1,从而将加油站也加入图中。为了后续构建图方便,将房屋也加入map中,即1对应1。
选出最佳站点,自然是要遍历每个站点,对每个站点都要进行迪杰斯特拉得到dist数组。然后根据题意筛选合适的站点,再根据题目优先级排序,输出第一个站点相关值即可。为了输出方便,用res结构体数组存储满足条件的站点,再sort排序。
知识点
保留一位小数可以用<cmath>中的round()函数,先乘以10,四舍五入为整数后,再除以10。
代码
#include <iostream>
#include <vector>
#include <climits>
#include <map>
#include <string>
#include <algorithm>
#include <cmath>
using namespace std;
int n, m, k, d, num;
int g[1015][1015] = {0};
map<string, int> mp; // 各节点的名字索引对照
vector<int> dist;
struct sta{
string id;
double minDis; // 到各房屋的最小距离
double avgDis; // 到各房屋的平均距离
};
vector<sta> res;
void dijie(int start){
dist[start] = 0;
bool visited[1015] = {false};
for (int cnt = 0; cnt < num; cnt++){
int now = -1, minl = INT_MAX;
for (int i = 1; i <= num; i++){
if (!visited[i] && dist[i] < minl){
minl = dist[i];
now = i;
}
} // 找到要激活的节点
if (now == -1){
return;
}
visited[now] = true;
for (int i = 1; i <= num; i++){
if (!visited[i] && g[now][i] < INT_MAX){
dist[i] = min(dist[i], dist[now] + g[now][i]);
}
} // 更新最短路径
}
}
bool cmp(sta x, sta y){
if (x.minDis != y.minDis)
return x.minDis > y.minDis; // 先比较最小距离
if (x.avgDis != y.avgDis)
return x.avgDis < y.avgDis; // 再比较平均距离
return x.id < y.id; // 最后按 ID 排序
}
int main(){
cin >> n >> m >> k >> d;
num = n + m;
for (int i = 1; i <= n; i++){
string s = to_string(i); // 用to_string()将数字转换为字符串
mp[s] = i;
}
for (int i = 1; i <= m; i++){
string s = "G" + to_string(i);
mp[s] = n + i;
} // 构造map
for (int i = 1; i <= num; i++){
for (int j = 1; j <= num; j++){
g[i][j] = (i == j) ? 0 : INT_MAX;
}
} // 初始化图
for (int i = 0; i < k; i++){
string p1, p2;
int dis;
cin >> p1 >> p2 >> dis;
g[mp[p1]][mp[p2]] = g[mp[p2]][mp[p1]] = dis;
} // 构造图
dist.resize(num + 1);
for (int i = n + 1; i <= num; i++){
fill(dist.begin(), dist.end(), INT_MAX); // 重置dist数组
dijie(i);
int sum = 0, maxl = 0, minl = INT_MAX;
for (int j = 1; j <= n; j++){
sum += dist[j];
maxl = max(maxl, dist[j]);
minl = min(minl, dist[j]);
} // 距离该站点最远房屋的距离和最近房屋的距离
if (maxl <= d){
string name = "G" + to_string(i - n);
sta node = {name, minl, sum * 1.0 / n};
res.push_back(node);
} // 满足条件的站点加入res数组
}
if ((int)res.size()){
sort(res.begin(), res.end(), cmp);
cout << res[0].id << endl;
res[0].avgDis = round(res[0].avgDis * 10) / 10.0; // 先乘以10,用round()四舍五入到整数,再除以10
printf("%.1lf %.1lf", res[0].minDis, res[0].avgDis);
}else{
cout << "No Solution";
}
return 0;
}