PAT A1072 Gas Station (30 分) 图 dijkstra

        题目大意:给出一张图的顶点和边的信息。顶点1~N是居民区,N+1~N+M是加油站,每个加油站的覆盖范围是DS。现在要求找到符合以下条件的加油站:到居民区的最短距离尽可能大,但必须保证每个居民区都能覆盖。如果这样的加油站不止一个(意为到居民区的最短距离最大的加油站不止一个),选取到居民区的平均距离最小的那个。如果这样的加油站还是不止一个,选取编号最小的那个。

总体思路是,对于每一个加油站,进行一次dijkstra算法,得到该加油站到所有居民区的最短距离,然后根据要求进行判断:①能否覆盖所有居民区?即所有最短距离中的最大值应<=DS。② 是否离居民区尽可能远?即所有最短距离中的最小值应当比记录的最短距离的最小值要大。③ 如果和记录的最短距离最小值相等,那么判断到所有居民区的平均距离是否是最小的。④ 选取编号最小的那个,这一条因为遍历顺序是 N+1 ~ N+M, 只要控制更新解的条件是满足前三条,最后输出的解一定是编号最小的。

PAT上的测试数据似乎坑不多,但是牛客网上本题的测试数据有坑点,表现在可能出现 G[A] G[A] 10 或者 G[A] G[B] 20; G[A] G[B] 30; 这样的数据。对应措施是:输入时,首先要判断这两个顶点是否是同一个点,不是同一个点的情况下才能存储。其次,这两个点如果重复出现过,判断它们之间的距离是否已经比这次的输入距离要小,如果是,就忽略这次输入,即重复输入的顶点对,它们的距离取最小的那个。

最后还有一个坑点,题目要求精确到1位小数,但是从给出的示例的输出结果来看,3.25被输出了3.3,应当是四舍五入。如果用“%.1f",实现的是”四舍六入五成双“,即输出3.2。所以我用的round函数实现的四舍五入,round(double* 10) / 10。但实际上使用"%.1f"也能过。非常奇怪,可能测试点里没有第二位小数是5的情形吧。

AC代码:

#include 
#include 
#include 
#include 
#include 


using namespace std;

const int MAXN = 1100;
const int INF = 0x7FFFFFFF;
int Graph[MAXN][MAXN];
vector G[MAXN];
int d[MAXN] = {0};
bool visited[MAXN] = {false};

void dijkstra(int s, int N, int houseNum, int &minDis, int &maxDis, double &avgDis)
{
    fill(d, d + MAXN, INF);
    fill(visited, visited + MAXN, 0);
    d[s] = 0;
    for (int i = 1; i <= N; ++i)
    {
        int u = -1, min = INF;
        for (int j = 1; j <= N; ++j)
        {
            if(!visited[j] && d[j] < min)
            {
                min = d[j];
                u = j;
            }
        }
        if(u == -1) return;
        visited[u] = true;
        for (int k = 0; k < G[u].size(); ++k)
        {
            int v = G[u][k];
            if(!visited[v] && d[v] > d[u] + Graph[u][v])
                d[v] = d[u] + Graph[u][v];
        }
    }
    sort(&d[1], &d[houseNum + 1]);
    minDis = d[1];
    maxDis = d[houseNum];
    for (int i = 1; i <= houseNum; ++i)
        avgDis += d[i] * 1.0 / houseNum;
}

int main()
{
    fill(Graph[0], Graph[0] + MAXN * MAXN, INF);
    int N, M, K, DS;
    scanf("%d%d%d%d", &N, &M, &K, &DS);
    for (int i = 0; i < K; ++i)
    {
        char s1[10], s2[10];
        int u, v, dis;
        scanf("%s %s %d", s1, s2, &dis);
        string str1 = string(s1), str2 = string(s2);
        if(str1[0] == 'G') u = N + stoi(str1.substr(1, str1.size() - 1));
        else u = stoi(str1);
        if(str2[0] == 'G') v = N + stoi(str2.substr(1, str2.size() - 1));
        else v = stoi(str2);
        if(u != v)
        {
            G[u].push_back(v);
            G[v].push_back(u);
            if(dis < Graph[u][v]) Graph[u][v] = Graph[v][u] = dis;
        }
    }
    int index = -1, minimumDis = 0;
    double minAvgDis = 1e10;
    for (int i = N + 1; i <= N + M; ++i)
    {
        int minDis = 0, maxDis = INF;
        double avgDis = 0;
        dijkstra(i, N + M, N, minDis, maxDis, avgDis);
        if(maxDis <= DS)
        {
            if(minDis > minimumDis)
            {
                index = i;
                minimumDis = minDis;
                minAvgDis = avgDis;
            }
            else if(minDis == minimumDis && avgDis < minAvgDis)
            {
                index = i;
                minAvgDis = avgDis;
            }
        }
    }
    if(index > -1) printf("G%d\n%.1f %.1f", index - N, minimumDis * 1.0, minAvgDis);
    else printf("No Solution");
    return 0;
}


 

你可能感兴趣的:(PAT)