【PAT甲级 最短路径 C++】1072 Gas Station (30 分)

Dijkstra

# include <iostream>
# include <algorithm>
# include <numeric>
# include <vector>
# include <set>

using namespace std;

/* 大约就是加油站要覆盖所有的居民区,然后挑选出距离加油站最近的居民楼的距离最大的加油站(大约这样污染较少) 
如果这个最大最近距离相等的话,就选择加油站到所有居民楼的平均距离更小的那个加油站
*/

const int MAXV = 1020; // 房屋和加油站的最大数
const int INF  = 0xffffff;

struct Node{int v, dis;};

int N, M, K, Ds;

vector<Node> G[MAXV];
set<int> gasStation; // AC之后觉得set并且没必要在定义容器(很多余),但是懒得改了
int dist[MAXV];
bool vis[MAXV];

// 因为非加油站的数量为N,这些编号又是从1开始,所以加上N就是加油站的编号
int getID(string S){
    return S[0] == 'G' ? N + stoi(S.substr(1)) : stoi(S);
}

void Dijkstra(int s){
    fill(dist, end(dist), INF);
    fill(vis, end(vis), false);
    dist[s] = 0;

    for(int i = 1;i <= N+M;++i){ // 因为可以通过去加油站有更短句路径,所以要加上M
        int u = -1;
        int MIN = INF;
        for(int j = 1;j <= N+M;++j){ // 因为可以通过去加油站有更短句路径,所以要加上M
            if(vis[j] == false && dist[j] < MIN){
                u = j;
                MIN = dist[j];                
            }
        }
        if(u == -1) return;
        vis[u] = true;
        for(Node next: G[u]){
            int v = next.v, uv_dis = next.dis;
            if(vis[v] == false){
                if(dist[u] + uv_dis < dist[v]){
                    dist[v] = dist[u] + uv_dis;
                }
            }
        }
    }
}

int main(){
    cin >> N >> M >> K >> Ds;
    for(int i = 0;i < K;++i){
        string SID1, SID2;
        int Dist;
        cin >> SID1 >> SID2 >> Dist;
        // 将 数字字符串 或 G1 等转换为int
        int ID1 = getID(SID1);
        int ID2 = getID(SID2);
        if(ID1 > N) gasStation.insert(ID1);
        if(ID2 > N) gasStation.insert(ID2);
        G[ID1].push_back({ID2, Dist});
        G[ID2].push_back({ID1, Dist});
    }

    int minStation = -1; // 最优加油站编号
    double maxDist = -1; // 最大的居民楼最近距离
    double minAvg = INF; // 最小居民楼平均距离
    for(int station: gasStation){ // 枚举所有加油站的编号
        Dijkstra(station); // 获得了当前station的dist数组
        int flag = 0;
        double dis = INF, avg = 0.0;
        for(int j = 1;j <= N;++j){
            if(dist[j] > Ds){ // 有居民楼超出距离
                flag = -1;
                break;
            }
            if(dist[j] < dis) dis = dist[j]; // 寻找当前station距离最近居民楼的距离
            avg += 1.0*dist[j] / N; // 计算平均数的sum
        }

        if(flag == -1) continue;
        if(dis > maxDist){ // 挑选出 max(最近居民楼的距离)
            maxDist = dis;
            minAvg = avg;
            minStation = station;
        }
        else
        if(dis == maxDist){
            if(avg < minAvg){
                minAvg = avg;
                minStation = station;
            }
        }
        
    }
    if(minStation == -1) {
        cout << "No Solution\n";
    }
    else { 
        cout << "G" << minStation - N << endl;
        printf("%.1f %.1f\n", maxDist, minAvg);
    }


    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值