1072. Gas Station (30)

题目链接:http://www.patest.cn/contests/pat-a-practise/1072
题目:

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 (<= 103), the total number of houses; M (<= 10), the total number of the candidate locations for the gas stations; K (<= 104), the number of roads connecting the houses and the gas stations; and DS, 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

分析:
这个排序比较复杂,也比较难以理解
用floyd算法,得出备选加油站到各个居住点之间的距离,然后在其中
0)要先筛选出符合条件的(即与居住点的距离都在服务范围内的)
1)以其中距离居住点距离最短距离中最大的为优(即题目中any of the residential housing is as far away as possible. )
2)如果1)有多个,则选择其中与所有居住点平均距离最短的( If there are more than one solution, output the one with the smallest average distance to all the houses)
3)如果1)和2)都得不出,则选出加油站编号最小的(If such a solution is still not unique, output the one with the smallest index number.)
按题目中Sample1举例子,
最后G1到居住点的距离为:4 2 4 3
G2到居住点的距离为:3 1 3 4
G3到居住点的距离为:5 3 2 4
首先,它们的距离都在服务距离5之内,都符合0)
在选出其中与居住点最短距离中最大的,G1的最短距离为2,G2的为1,G3为2,所以G2淘汰了,G1和G3留下来
接下来比较第2)步,平均距离,G1到居住点的平均距离为13 / 3,而G3为14 / 3,所以选择G1。并且输出最短距离2和13 / 3也就是3.3。
AC代码:
#include<stdio.h>
#include<string>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct GasStation{
 float mini;
 float average;
 int id;
};
vector<GasStation>V;
bool cmp(GasStation A, GasStation B){
 if (A.mini != B.mini)return A.mini > B.mini; //注意这里是>号,选最小距离的最大值
 else if (A.average != B.average)return A.average < B.average;
 else return A.id < B.id;
}//自定义比较函数,按照分析中的来,先最短距离的最大,再选最小的平均距离,再选最小的下标值
int main(void){
 freopen("F://Temp/input.txt", "r", stdin);
 int N, M, K, Ds;
 scanf("%d%d%d%d", &N, &M, &K, &Ds);
 int all_point = N + M;//所有站点,包括居住点和加油站
 int dis[1012][1012];//*注意这里
 for (int i = 1; i <= all_point; i++){
  for (int j = 1; j <= all_point; j++){
   dis[i][j] = -1;
  }
  dis[i][i] = 0;
 }
 for (int i = 0; i < K; i++){
  int s, t, cost;
  //scanf("%d%d%d", &s, &t, &cost);
  string str_s, str_t;//先以字符串存储,因为可能有G加油站
  cin >> str_s >> str_t >> cost;
  if (str_s[0] == 'G'){
   str_s = str_s.substr(1);//如果第一个字母是G,则截取掉
   s = atoi(str_s.c_str()) + N;//第i个加油站Gi对应与编号(N + i)
  }
  else
   s = atoi(str_s.c_str());//atoi(char *),把字符串变为int,因为里面是char *,所以需要str.c_str()转换
  if (str_t[0] == 'G'){
   str_t = str_t.substr(1);//如果第一个字母是G,则截取掉
   t = atoi(str_t.c_str()) + N;//第i个加油站Gi对应与编号(N + i)
  }
  else
   t = atoi(str_t.c_str()); //atoi(char *),把字符串变为int,因为里面是char *,所以需要str.c_str()转换
  dis[s][t] = cost;
  dis[t][s] = cost;
 }//get the roads : input
 for (int k = 1; k <= all_point; k++){
  for (int i = 1; i <= all_point; i++){
   for (int j = 1; j <= all_point; j++){
    if (dis[i][k] == -1 || dis[k][j] == -1)continue;
    if (dis[i][j] == -1 || dis[i][j] > dis[i][k] + dis[k][j]){
     dis[i][j] = dis[i][k] + dis[k][j];
     dis[j][i] = dis[i][j];
    }
   }
  }
 }//for-------floyd
 for (int i = N + 1; i <= N + M; i++){
  int sum = 0;
  int min = 1 << 30;
  bool isGasStation = true;//是否能作为一个加油站,即所有距离是否都在服务范围内
  for (int j = 1; j <= N; j++){
   if (dis[i][j] > Ds){
    isGasStation = false;//距离大于服务范围,不能合格
    break;
   }
   sum += dis[i][j];
   if (min > dis[i][j])
    min = dis[i][j];
  }
  if (isGasStation){
   GasStation tmp;
   tmp.id = i - N;
   tmp.mini = min * 1.0;
   tmp.average = sum * 1.0 / N;
   V.push_back(tmp);//把合格的加油站都记录放入vector中
  }
 }
 if (V.size() == 0){
  printf("No Solution\n");
 }//注意边界条件,当V中无解时输出No Solution
 else{
  sort(V.begin(), V.end(), cmp);
  printf("G%d\n%.1f %.1f\n", V[0].id, V[0].mini, V[0].average);
 }
 return 0;
}
先是用floid做的,但是太耗时了,案例5运行超时了。改写了代码为dijkstra。
#include<stdio.h>
#include<string>
#include<iostream>
#include<vector>
#include<algorithm>
#include<string.h>//memset()
using namespace std;
struct GasStation{
 float mini;
 float average;
 int id;
};
vector<GasStation>V;
bool cmp(GasStation A, GasStation B){
 if (A.mini != B.mini)return A.mini > B.mini; //注意这里是>号,选最小距离的最大值
 else if (A.average != B.average)return A.average < B.average;
 else return A.id < B.id;
}//自定义比较函数,按照分析中的来,先最短距离的最大,再选最小的平均距离,再选最小的下标值
bool mark[1012];
int Dis[1012];//用来存放加油站到各个居住点的距离
//void Dij(int start, int ds[][1012],int N,int M){//这种也是可以的,但是不能int **ds或int ds[][]
void Dij(int start, int (*ds)[1012], int N, int M){//当以二位数组作为参数的时候,可以用上面或这里的两种方式,注意一定要指明纵坐标值
 mark[start] = true;
 int newP = start;
 Dis[start] = 0;
 for (int j = 1; j <= N + M; j++){//一共进行N + M次循环就能找出一个加油站出发的所有距离
  for (int i = 1; i <= N + M; i++){
   if (mark[i] || ds[newP][i] == -1)continue;
   else if (Dis[i] == -1 || Dis[i] > Dis[newP] + ds[newP][i]){
    Dis[i] = Dis[newP] + ds[newP][i];
   }
  }
  int min = 1 << 30;
  for (int i = 1; i <= N + M; i++){
   if (mark[i] || Dis[i] == 0 || Dis[i] == -1)continue;
   if (Dis[i] < min){
    min = Dis[i];
    newP = i;
   }
  }
  mark[newP] = true;
 }
 for (int j = 1; j <= N + M; j++){//把
  if (start != j){
   ds[start][j] = Dis[j];
   ds[j][start] = Dis[j];
  }
 }
}
int main(void){
 freopen("F://Temp/input.txt", "r", stdin);
 int N, M, K, Ds;
 scanf("%d%d%d%d", &N, &M, &K, &Ds);
 int all_point = N + M;//所有站点,包括居住点和加油站
 int dis[1012][1012];
 for (int i = 1; i <= all_point; i++){
  for (int j = 1; j <= all_point; j++){
   dis[i][j] = -1;
  }
  dis[i][i] = 0;
 }
 for (int i = 0; i < K; i++){
  int s, t, cost;
  //scanf("%d%d%d", &s, &t, &cost);
  string str_s, str_t;//先以字符串存储,因为可能有G加油站
  cin >> str_s >> str_t >> cost;
  if (str_s[0] == 'G'){
   str_s = str_s.substr(1);//如果第一个字母是G,则截取掉
   s = atoi(str_s.c_str()) + N;//第i个加油站Gi对应与编号(N + i)
  }
  else
   s = atoi(str_s.c_str());//atoi(char *),把字符串变为int,因为里面是char *,所以需要str.c_str()转换
  if (str_t[0] == 'G'){
   str_t = str_t.substr(1);//如果第一个字母是G,则截取掉
   t = atoi(str_t.c_str()) + N;//第i个加油站Gi对应与编号(N + i)
  }
  else
   t = atoi(str_t.c_str()); //atoi(char *),把字符串变为int,因为里面是char *,所以需要str.c_str()转换
  dis[s][t] = cost;
  dis[t][s] = cost;
 }//get the roads : input
 /*	for (int k = 1; k <= all_point; k++){
 for (int i = 1; i <= all_point; i++){
 for (int j = 1; j <= all_point; j++){
 if (dis[i][k] == -1 || dis[k][j] == -1)continue;
 if (dis[i][j] == -1 || dis[i][j] > dis[i][k] + dis[k][j]){
 dis[i][j] = dis[i][k] + dis[k][j];
 dis[j][i] = dis[i][j];
 }
 }
 }
 }//for-------floyd	 */
 for (int i = N + 1; i <= N + M; i++){
  memset(mark, false, sizeof(mark));
  memset(Dis, -1, sizeof(Dis));
  Dij(i, dis,N,M);
 }//多源最短路径,需要循环,以及初始化
 for (int i = N + 1; i <= N + M; i++){
  int sum = 0;
  int min = 1 << 30;
  bool isGasStation = true;//是否能作为一个加油站,即所有距离是否都在服务范围内
  for (int j = 1; j <= N; j++){
   if (dis[i][j] > Ds){
    isGasStation = false;//距离大于服务范围,不能合格
    break;
   }
   sum += dis[i][j];
   if (min > dis[i][j])
    min = dis[i][j];
  }
  if (isGasStation){
   GasStation tmp;
   tmp.id = i - N;
   tmp.mini = min * 1.0;
   tmp.average = sum * 1.0 / N;
   V.push_back(tmp);//把合格的加油站都记录放入vector中
  }
 }
 if (V.size() == 0){
  printf("No Solution\n");
 }//注意边界条件,当V中无解时输出No Solution
 else{
  sort(V.begin(), V.end(), cmp);
  printf("G%d\n%.1f %.1f\n", V[0].id, V[0].mini, V[0].average);
 }
 return 0;
}
这里注意一下二维数组作为参数的注意点,可以参考: http://blog.csdn.net/caryaliu/article/details/8131408

截图:
1072. Gas Station (30)_第1张图片
1072. Gas Station (30)_第2张图片
——Apie陈小旭

你可能感兴趣的:(最短路径,pat)