题目链接
题目分析
给出M个加油站待选点和N个房屋,要求加油站距离最近的房子越远越好;(即最小距离中最大的那个)
当有相同解时,选择平均距离更小的那一个,若还有多解,选择编号更小的那一个
民房编号 1~N(1000)
; 气站编号G1~GM(10)
;
解题思路
对于所有候选站点,依次执行如下步骤:
Dijkstra()算法 查找最短路径,只需记录到每个结点的最短距离即可,不需要保存路径;每检查完一个待选点,判断:
1、检查是够全部在范围内,并记录最小距离
2、计算平均距离;
3、与已保存的最小距离比较
注意点:
1、候选气站点当也当作图中正常结点,其路径亦可使用;只是不要求其也在气站服务范围内!
2、最后一个测试点,候选站点的编号会达到 G10
,所以转化序号时要注意,不能简单用 id = str[1] - '0'
;
AC程序(C++)
/**********************************
*@ID: 3stone
*@ACM: PAT.A1072 Gas Station
*@Time: 18/8/21
*@IDE: VSCode 2018 + clang++
***********************************/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1030;
const int INF = 0x7fffffff;
int N, M, K;//民房数,待选气站数,边数,
int Max_Dis;//服务范围
int G[maxn][maxn]; //图
int d[maxn]; //最短距离
bool vis[maxn]; //标记是否访问
int Min_Dis, Min_Sum_Dis;
int best_station;
void Dijkstra(int s) {
//初始化起点
d[s] = 0.0;
for(int i = 1; i <= N + M; i++) { //遍历n+m次,每次取一个点
//选择最近点
int u = -1;
int temp_min = INF;
for(int j = 1; j <= N + M; j++) {
if(vis[j] == false && d[j] < temp_min) {
u = j;
temp_min = d[j];
}
}
if(u == -1) return;
vis[u] = true;
//更新最短距离 & 花费
for(int v = 1; v <= N + M; v++) {
if(vis[v] == false && G[u][v] != INF) { //只需保存最短路径长度即可
if(d[u] + G[u][v] < d[v]) {
d[v] = d[u] + G[u][v];
}
}
}//for - v
}//for - i
}//Dijkstra
void min_check(int s) {
int temp_min = INF;
int sum_dis = 0;
for(int i = 1; i <= N; i++ ) {
if(d[i] > Max_Dis) return; //有结点在服务区外,舍弃这个候选点
sum_dis += d[i];
if(d[i] < temp_min){
temp_min = d[i];
}
}
if(temp_min > Min_Dis) {
best_station = s;
Min_Dis = temp_min;
Min_Sum_Dis = sum_dis;
} else if(temp_min == Min_Dis && sum_dis < Min_Sum_Dis) {
best_station = s;
Min_Sum_Dis = sum_dis;
}
//还有多解,选择编号小的;本身就是从小到大check的,不用再加判断;
}
int get_id(char str[]) {
int len = strlen(str);
int ID = 0, i = 0;
if(str[0] == 'G') i = 1;
while(i < len)
ID = ID * 10 + (str[i++] - '0');
if(str[0] == 'G') return ID + N;
else return ID;
}
int main() {
char s1[5], s2[5];
int c1, c2;
int route_dis;
while(scanf("%d %d %d %d", &N, &M, &K, &Max_Dis) != EOF) {
//初始化
fill(G[0], G[0] + maxn * maxn, INF);
Min_Dis = -1;
Min_Sum_Dis = -1;
best_station = -1;
//输入路径信息
for(int i = 0; i < K; i++) {
scanf("%s %s %d", s1, s2, &route_dis);
c1 = get_id(s1);
c2 = get_id(s2);
G[c1][c2] = route_dis;//无向图
G[c2][c1] = route_dis;
}
for(int i = 1; i <= M; i++) { //依次检查各个待选点
//初始化
fill(vis, vis + maxn, false);
fill(d, d + maxn, INF);
Dijkstra(N + i);
min_check(N + i);
}
if(best_station == - 1)
printf("No Solution\n");
else {
printf("G%d\n", best_station - N);
printf("%.1f %.1f\n", (double)Min_Dis, (double)Min_Sum_Dis / N);
}
}//while
return 0;
}