*PAT_甲级_1072 Gas Station (30point(s)) (C++)【Dijkstra/字符串截取/与数字相互转换】

目录

1,题目描述

题目大意

注意:

2,思路

数据结构

算法

3,AC代码

4,解题过程

第一搏

第二搏


1,题目描述

*PAT_甲级_1072 Gas Station (30point(s)) (C++)【Dijkstra/字符串截取/与数字相互转换】_第1张图片

 

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

题目大意

从给定的几个站点中,寻找最合适的加油站站点。该站点需满足:距离所有house不得超过服务范围Ds;取加油站距离最近house(距离为minDis)最大的的站点;若不唯一,则取加油站距所有house平均距离最小的站点 ;仍不唯一,取id最小的。

 

注意:

  1. the minimum distance between the station and any of the residential housing is as far away as possible:这是选择加油站的第一参考(优先级最高):距离house最短距离越大越好;
  2.  If there are more than one solution, output the one with the smallest average distance to all the houses:第二参考,平均距离越小越好

 

2,思路

数据结构

  • int N, M, K, Ds;        //N房子数目 M侯选位置数目 K路的数目 Ds加油站服务范围 
  • struct node{int id; float minDis = INT_MAX, maxDis = 0, totalDis = 0;}:候选站点的编号、与最近house的距离、与最远house的距离(判断是否满足条件时用)、距离所有house距离之和;
  • int graph[1020][1020]:存放所有路径距离信息(站点与站点,站点与house,house与house);
  • int dis[1020]:(Dijkstra算法基本操作)在每次Dijkstra算法中,存放起点与各点之间的最短距离;
  • bool visited[1020]:(Dijkstra算法基本操作)判断节点是否已被访问;
  • vector ans:存放符合基本条件(所有house都在加油站的服务范围之内)的站点信息;

算法

  1. 将所有的house和station看作点,构造图graph(节点的编号先按字符串处理,若第一个字符为'G'则消去首字符,其余字符转换为数字,并且加上N(输出时,减去N即可还原) ;否则直接转换为数字即可);
  2. 设计Dijkstra函数,并且统计与最近house的距离minDis、与最远house的距离(判断是否满足条件时用)maxDis、距离所有house距离之和totalDis(计算平均距离)*PAT_甲级_1072 Gas Station (30point(s)) (C++)【Dijkstra/字符串截取/与数字相互转换】_第2张图片
  3. 对每一个候选站点都使用一次Dijkstra算法,将所有符合基本条件的站点存入ans中;
  4. 按照排序函数进行排序;*PAT_甲级_1072 Gas Station (30point(s)) (C++)【Dijkstra/字符串截取/与数字相互转换】_第3张图片
  5. 若ans为空,输出No Solution;否则输出ans[0]相关信息即可;*PAT_甲级_1072 Gas Station (30point(s)) (C++)【Dijkstra/字符串截取/与数字相互转换】_第4张图片

 

3,AC代码

#include
using namespace std;

struct node{
    //id指明哪个站点 minDis距离house的最短距离 maxDis加油站距house最远距离 totalDis距离house的总距离
    int id;
    float minDis = INT_MAX, maxDis = 0, totalDis = 0;
};
vector ans;       //存放合适站点的信息

int N, M, K, Ds;        //N房子数目 M侯选位置数目 K路的数目 Ds加油站服务范围
int graph[1020][1020];
int dis[1020];
bool visited[1020];

void Dijkstra(int start){
    fill(dis, dis + 1020, INT_MAX);
    fill(visited, visited + 1020, false);
    node n;
    n.id = start;
    dis[start] = 0;

    for(int i = 1; i <= N + M; i++){
        int minDis = INT_MAX, u = -1;
        for(int j = 1; j <= N + M; j++){
            if(visited[j] == false && dis[j] < minDis){
                u = j;
                minDis = dis[j];
            }
        }
        if(u == -1) break;//
        visited[u] = true;
        if(u <= N){         //将加油站与house相连的路进行判断更新
            n.totalDis += 1.0 * minDis;
            if(minDis < n.minDis) n.minDis = 1.0 * minDis;
            if(minDis > n.maxDis) n.maxDis = 1.0 * minDis;
        }
        for(int v = 1; v <= M + N; v++){
            if(visited[v] == false && graph[u][v] != INT_MAX){
                if(dis[v] > dis[u] + graph[u][v]){
                    dis[v] = dis[u] + graph[u][v];
                }
            }
        }
    }
    if(n.maxDis <= Ds) ans.push_back(n);
}
bool cmp1(node a, node b){
    if(a.minDis != b.minDis)
        return a.minDis > b.minDis;
    else{
        if(a.totalDis != b.totalDis)
            return a.totalDis < b.totalDis;
        else return a.id < b.id;
    }
}
int main(){
#ifdef ONLINE_JUDGE
#else
    freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE

    string s1, s2;
    int a, b, d;
    scanf("%d %d %d %d", &N, &M, &K, &Ds);
    fill(graph[0], graph[0] + 1020 * 1020, INT_MAX);
    for(int i = 0; i < K; i++){
        cin>>s1>>s2>>d;
        if(s1[0] == 'G'){
            s1 = s1.substr(1);      //提取从1往后的字符串
            a = N + stoi(s1);
        }
        else a = stoi(s1);
        if(s2[0] == 'G'){
            s2 = s2.substr(1);
            b = N + stoi(s2);
        }
        else b = stoi(s2);
        if(graph[a][b] > d)         //两点之间可能不止一条路 选择最短的一条
            graph[a][b] = graph[b][a] = d;
    }

    for(int i = N + 1; i <= N + M; i++)
        Dijkstra(i);

    if(ans.size() == 0) printf("No Solution");
    else{
        sort(ans.begin(), ans.end(), cmp1);
        printf("G%d\n%.1f %.1f", ans[0].id-N, ans[0].minDis, ans[0].totalDis / N);
    }

    return 0;
}

 

4,解题过程

第一搏

字符串转数字废了好多时间(还是不够熟悉。。。),不熟悉的同学可以看这里@Miserable_ccf【C++中的字符串(String)和数值转换】;

本想使用原先的方法,确定string类型变量的大小(resize()),再使用scanf函数(速度比较快)。然而会这样:

*PAT_甲级_1072 Gas Station (30point(s)) (C++)【Dijkstra/字符串截取/与数字相互转换】_第5张图片

改用cin后就可以了:

*PAT_甲级_1072 Gas Station (30point(s)) (C++)【Dijkstra/字符串截取/与数字相互转换】_第6张图片 

第二搏

程序修改后基本没什么问题了,但是在四舍五入输出的时候却出现了奇怪现象:

codeblock中运行后,3.25输出的是3.2

*PAT_甲级_1072 Gas Station (30point(s)) (C++)【Dijkstra/字符串截取/与数字相互转换】_第7张图片

(上网查了下,数据输出时,自动四舍五入)提交时果然全部通过。

*PAT_甲级_1072 Gas Station (30point(s)) (C++)【Dijkstra/字符串截取/与数字相互转换】_第8张图片

可能是编译器选项设置的问题吧。。。(小本本记下了) 

你可能感兴趣的:(PAT甲级,PAT,甲级,C++,1072,Dijkstra,字符串截取)