一、技术总结
- 第一点是关于图的编号如何处理,因为气站混合在图中,同时编号带有因为字母,所以解决办法是把气站编号依次往居民编号后加即n+1开始。需要编写getID函数,将字符变为数字的公式为int ID = 0; ID = ID * 10 + (str[i]-'0');,具体参考代码处
- 第二点要注意题中要求,初始结点下标是从1开始还是从0开始,从而决定i <= n还是i < n,这点尤为重要,在编写Djikstra函数时。
- 还有就是题中的限制条件,这一步需要我们去仔细审读题目,查看样例。
二、参考代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1015;
const int INF = 0x3fffffff;
int G[MAXN][MAXN], d[MAXN];
bool vis[MAXN] = {false};
int n, m, k, ds;
//avgDis是符合站点要求到每个居民家的平均距离,
//ansMax是每个站点最短距离中的最大距离
//ansID最终存放加油站ID号
double avgDis = INF, ansMax = -1;
int ansID = -1;
void Djikstra(int s){
memset(vis, false, sizeof(vis));
fill(d, d+MAXN, INF);
d[s] = 0;
for(int i = 0; i < n+m; i++){
int u = -1, MIN = INF;
for(int j = 1; j <= n+m; j++){
if(vis[j] == false && d[j] < MIN){
u = j;
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];
}
}
}
}
}
//将str[]转换为数字,若str是数字,则返回本身,否则返回去掉G之后的数字加上n
int getID(char str[]){
int i = 0, len = strlen(str), ID = 0;
while(i < len){
if(str[i] != 'G'){
ID = ID * 10 + (str[i] - '0');
}
i++;
}
if(str[0] == 'G') return n + ID;
else return ID;
}
int main(){
scanf("%d%d%d%d", &n, &m, &k, &ds);
int u, v, w;
char c1[5], c2[5];
fill(G[0], G[0]+MAXN*MAXN, INF);
for(int i = 1; i <= k; i++){
scanf("%s %s %d", c1, c2, &w);
u = getID(c1);
v = getID(c2);
G[v][u] = G[u][v] = w;
}
//遍历所有加油站
for(int i = n+1; i <= n+m; i++){
double minDis = INF, avg = 0;//minDis为最大的最近距离, avg为平均距离
Djikstra(i);
for(int j = 1; j <= n; j++){
if(d[j] > ds){
minDis = -1;
break;
}
if(d[j] < minDis) minDis = d[j];
avg += 1.0 * d[j] / n;//获取平均距离
}
if(minDis == -1) continue;
if(minDis > ansMax){//更新最大距离
ansID = i;
ansMax = minDis;
avgDis = avg;
}else if(minDis == ansMax && avg < avgDis){
ansID = i;
avgDis = avg;
}
}
if(ansID == -1) printf("No Solution\n");
else{
printf("G%d\n", ansID-n);
printf("%.1f %.1f\n", ansMax, avgDis);
}
return 0;
}