PAT甲級真題 1072 Gas Station (30分) C++實現(Dijkstra算法,測試點4四捨五入的坑)

題目

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 (≤1000), the total number of houses; M (≤10), the total number of the candidate locations for the gas stations; K (≤10000​​ ), 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

思路

首先處理輸入中加油站的編號“G1~G10”,將其統一編號到房子之後,比如G1視爲n+1。

一開始用Floyd算法求多源最短路徑,果斷超時了。

改用Dijkstra算法,以每個加油站爲源點求單源最短路徑,由於m最大值爲10,最多隻需求10次,解決了超時問題。

對於dist[Gi],檢查其與所有房子之間最小距離dist[Gi][i],若其中有超過Ds的,則放棄該選擇;若所有距離均在Ds內,則記錄其中的最小值minGi 和平均距離 aveGi。

從所有minGi中找最大的;若有並列,再順序找出其中aveGi最小的第一個即爲所求。

坑點

  1. 一開始測試點4出現運行時錯誤,原因是將節點編號當做了最多2位,其實它們最大能取到1000 G10 這樣的,需要將除了’G’以外的所有字符串轉換爲數字。

  2. 測試點4一直答案錯誤。一開始輸出最後結果時爲了四捨五入,將平均值加上了0.05後再用"%.1f"打印;看了網上許多代碼發現並沒有採用+0.05的方式,而是隻有“%.1f”。查了資料發現%.1f會自動執行四捨五入的操作,但經過測試,值時3.25時打印出的是3.2,3.26時打印出3.3,值爲3.251時也打印出3.3。當結果正好是X.X5時,%.1f的四捨五入結果是不對的。

去掉+0.05後,輸入測試用例1,結果如下(調試環境:Mac XCode):
XCode輸出結果
而題目中給的卻是:
G1
2.0 3.3

然而這時卻能AC了,測試點4不再報錯……

有點神奇。如有知道問題原因的請不吝賜教。

代碼

#include <iostream>
#include <vector>
#include <climits>
using namespace std;

struct Solution{  //可行解
    int index;
    float minDist;
    float average;
};
int main(){
    int n, m, k, ds;
    scanf("%d %d %d %d", &n, &m, &k, &ds);
    //建立鄰接矩陣
    vector<vector<int> > E(n+m+1, vector<int>(n+m+1, INT_MAX));
    for (int i=0; i<k; i++){
        char a[5], b[5];  //最多要裝1000,字符串大小應>=4
        int u, v, d;
        scanf("%s %s %d", a, b, &d);
        u = a[0]=='G' ? n+atoi(&a[1]) : atoi(a);
        v = b[0]=='G' ? n+atoi(&b[1]) : atoi(b);
        E[u][v] = E[v][u] = d;
    }
    //Dijkstra算法求最短路徑
    vector<vector<int> > dist(m+1, vector<int>(n+m+1, INT_MAX));
    for (int i=1; i<=m; i++){
        vector<bool> visited(n+m+1);
        dist[i][n+i] = 0;
        for (int l=1; l<=m+n; l++){
            int minDist = INT_MAX;
            int minI = -1;
            for (int j=1; j<=n+m; j++){
                if (!visited[j] && dist[i][j]<minDist){
                    minDist = dist[i][j];
                    minI = j;
                }
            }
            if (minI == -1){
                break;
            }
            visited[minI] = true;
            for (int j=1; j<=n+m; j++){
                if (!visited[j] && minDist!=INT_MAX && E[minI][j]!=INT_MAX && minDist+E[minI][j]<dist[i][j]){
                    dist[i][j] = minDist + E[minI][j];
                }
            }
        }
    }

    //記錄所有可行解
    vector<Solution> S;
    for (int i=1; i<=m; i++){
        float minDist = INT_MAX;
        float sum = 0.0;
        for (int j=1; j<=n; j++){
            if (dist[i][j] > ds){
                minDist = 0;
                break;
            }
            if (dist[i][j] < minDist) {
                minDist = dist[i][j];
            }
            sum += dist[i][j];
        }
        if (minDist > 0){
            S.push_back({i, minDist, sum/n});
        }
    }

    if (S.size() == 0){
        printf("No Solution\n");
    }
    else{
        //找出其中最小距離最遠,平均距離最小的第一個
        Solution bestS = S[0];
        for (int i=1; i<S.size(); i++){
            if (S[i].minDist>bestS.minDist || (S[i].minDist==bestS.minDist && S[i].average<bestS.average)){
                bestS = S[i];
            }
        }
        printf("G%d\n%.1f %.1f\n", bestS.index, bestS.minDist, bestS.average);  //平均距離四捨五入
    }
    return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章