1072 Gas Station (30 分)

A gas station has to be built at such a location that the minimum distance between the station and any of the residential housing is as far away as possible. However it must guarantee that all the houses are in its service range.

Now given the map of the city and several candidate locations for the gas station, you are supposed to give the best recommendation. If there are more than one solution, output the one with the smallest average distance to all the houses. If such a solution is still not unique, output the one with the smallest index number.

Input Specification:
Each input file contains one test case. For each case, the first line contains 4 positive integers: N (≤10
​3
​​ ), the total number of houses; M (≤10), the total number of the candidate locations for the gas stations; K (≤10
​4
​​ ), the number of roads connecting the houses and the gas stations; and D
​S
​​ , the maximum service range of the gas station. It is hence assumed that all the houses are numbered from 1 to N, and all the candidate locations are numbered from G1 to GM.

Then K lines follow, each describes a road in the format

P1 P2 Dist
where P1 and P2 are the two ends of a road which can be either house numbers or gas station numbers, and Dist is the integer length of the road.

Output Specification:
For each test case, print in the first line the index number of the best location. In the next line, print the minimum and the average distances between the solution and all the houses. The numbers in a line must be separated by a space and be accurate up to 1 decimal place. If the solution does not exist, simply output No Solution.

Sample Input 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
Sample Output 1:
G1
2.0 3.3
Sample Input 2:
2 1 2 10
1 G1 9
2 G1 20
Sample Output 2:
No Solution

题目大意:有gasStationNum个站点,有houseNum个居民楼。选择一个站点,使它到居民楼的最小距离最大。如果有多个,则选择距离所有居民楼平均距离最小的。如果仍有多个,则选择序号最小的。

分析:由于站点与站点,站点与居民楼之间也有距离,要将站点的信息也放入二维数组中。每次以不同的站点为起点,用迪杰斯特拉算法寻找最短路径。遍历dis数组,如果发现有一个值大于maxScale,则舍弃该站点。找到最短的路径长度,将每个站点的最短的路径长度比较,选择最大的。

输入:
我这里用二维数组存储路径信息,将houseNum个居民楼的信息放在前面,gasStationNum个站点的信息放在后面。用字符串接收,若第一个字符为G,判断为站点,放在后面。注意这里的站点和居民楼都可能是多位数,我这里选择用stoi函数,将数字字符串转化为数字(这一部分的转化参考了柳神的代码,少了这一步最后一个点过不去)

 scanf("%d %d %d %d", &houseNum, &gasStationNum, &roadNum, &maxScale);
  string a, b;
  int a2,b2,c;
  for (int i = 0; i < roadNum;i++){
    
    
    cin >> a >> b >> c;
    /*这里不能用scanf,scanf输入字符串是针对char*或char[]的,即scanf只能输入C语言中的内置数据
    同理,printf不能直接输出字符串,要用输入输出流*/
    if(a[0]=='G'){
    
    
      a = a.substr(1);//从位置1开始,取到末尾
      a2 = houseNum+stoi(a);//stoi用于将数字字符串转化成数字输出
    }
    else{
    
    
      a2 = stoi(a);
    }
    if(b[0]=='G'){
    
    
      b = b.substr(1);
      b2 = houseNum+stoi(b);
    }
    else{
    
    
      b2 = stoi(b);
    }
    road[a2][b2] = road[b2][a2] = c;
  }//前面的代表居民楼,后面的代表站点

迪杰斯特拉算法找最短路径:
这没啥好说的,不过是在外面多套个循环,查找多个结点的最短路径

 for (int i = houseNum + 1; i <= houseNum + gasStationNum;i++){
    
      
    //每次以不同的gasStation为起点寻找最短路径
    double mindis = inf, aver = 0;
    fill(minDis, minDis + 1011, inf);
    fill(visit, visit + 1011, false);
    minDis[i] = 0;
    for (int j = 0; j < houseNum + gasStationNum;j++){
    
    
      //gasStation也有路径长度,也要参与遍历
      int u = -1, minn = inf;
      for (int k = 1; k <= gasStationNum + houseNum;k++){
    
    
        if(visit[k]==false&&minDis[k]<minn){
    
    
          u = k;
          minn = minDis[k];
        }
      }
      if(u==-1)
        break;
      visit[u] = true;
      for (int k = 1; k <= houseNum + gasStationNum;k++){
    
    
        if(visit[k]==false&&minDis[u]+road[u][k]<minDis[k]){
    
    
          minDis[k] = minDis[u] + road[u][k];
        }
      }
    }

AC代码

#include<bits/stdc++.h>
using namespace std;

const int inf = 9999999;
int road[1011][1011], minDis[1011];
bool visit[1011];
int houseNum, gasStationNum, roadNum, maxScale;

int main(){
    
    
  fill(road[0], road[0] + 1011 * 1011, inf);//不存在的路径设置为inf,便于下面得到最短路径
  scanf("%d %d %d %d", &houseNum, &gasStationNum, &roadNum, &maxScale);
  string a, b;
  int a2,b2,c;
  for (int i = 0; i < roadNum;i++){
    
    
    cin >> a >> b >> c;
    /*这里不能用scanf,scanf输入字符串是针对char*或char[]的,即scanf只能输入C语言中的内置数据
    同理,printf不能直接输出字符串,要用输入输出流*/
    if(a[0]=='G'){
    
    
      a = a.substr(1);//从位置1开始,取到末尾
      a2 = houseNum+stoi(a);//stoi用于将数字字符串转化成数字输出
    }
    else{
    
    
      a2 = stoi(a);
    }
    if(b[0]=='G'){
    
    
      b = b.substr(1);
      b2 = houseNum+stoi(b);
    }
    else{
    
    
      b2 = stoi(b);
    }
    road[a2][b2] = road[b2][a2] = c;
  }//前面的代表居民楼,后面的代表站点
  int ansid=-1;
  double ansdis = -1, ansaver = inf;//便于下面寻找最短路径中的最大值
  for (int i = houseNum + 1; i <= houseNum + gasStationNum;i++){
    
      
    //每次以不同的gasStation为起点寻找最短路径
    double mindis = inf, aver = 0;
    fill(minDis, minDis + 1011, inf);
    fill(visit, visit + 1011, false);
    minDis[i] = 0;
    for (int j = 0; j < houseNum + gasStationNum;j++){
    
    
      //gasStation也有路径长度,也要参与遍历
      int u = -1, minn = inf;
      for (int k = 1; k <= gasStationNum + houseNum;k++){
    
    
        if(visit[k]==false&&minDis[k]<minn){
    
    
          u = k;
          minn = minDis[k];
        }
      }
      if(u==-1)
        break;
      visit[u] = true;
      for (int k = 1; k <= houseNum + gasStationNum;k++){
    
    
        if(visit[k]==false&&minDis[u]+road[u][k]<minDis[k]){
    
    
          minDis[k] = minDis[u] + road[u][k];
        }
      }
    }
    for (int k = 1; k <= houseNum;k++){
    
    //
      if(minDis[k]>maxScale){
    
    
        mindis = -1;
        break;
      }
      if(minDis[k]<mindis)
        mindis = minDis[k];//找到居民楼到一个站点的最小值
      aver += minDis[k] * 1.0;  
    }
    if(mindis==-1)
      continue;//此时代表有居民楼到站点的距离大于maxScale
    aver = aver / houseNum;
    if(mindis>ansdis){
    
    //发现更大的最小值
      ansdis = mindis;
      ansid = i;
      ansaver = aver;  
    }
    else if(mindis==ansdis&&aver<ansaver){
    
    //最小值相同,选择距离所有居⺠区距离平均值最⼩的
      ansid = i;
      ansaver = aver;
    }
  }
  if(ansid==-1)
    printf("No Solution");
  else{
    
    
    printf("G%d\n", ansid-houseNum);
    printf("%.1lf %.1lf", ansdis, ansaver);
  }
}

猜你喜欢

转载自blog.csdn.net/weixin_48954087/article/details/113763031
今日推荐