1072 Gas Station (30 分)

水~。

题意

有N所居民房、M个加油站待建点以及K条无向边。现在要从M个加油站待建点中选出一个来建造加油站,使得该加油站距离最近的居民房尽可能远,且必须保证所有房子与该加油站的距离都不超过给定的服务范围DS。现在给出N、M、K、DS,以及K条无向边的端点及边权,输出应当选择的加油站编号、与该加油站最近的居民房的距离、该加油站距离所有居民房的平均距离。

如果有多个最近距离相同的解,那么选择平均距离最小的;如果平均距离也相同,则选择编号最小的。

思路

  1. 首先要解决顶点的编号问题。对居民房来说,输入的编号就是它的编号;对加油站来说,输入的编号去掉最前面的'G'后就是它的编号,但是为了与居民房区分,需要把加油站的编号加上居民房的个数来作为加油站的编号。例如,如果有5个居民房、3个加油站,那么居民房的编号就是1 ~ 5,而加油站的编号就是6 ~ 8。因此需要按字符串的形式读入题目给定的编号,然后根据字符串首位是否为'G'来判断如何处理编号。
  2. 枚举每个加油站,使用Dijkstra算法来得到所有居民房距离该加油站的最短距离。但是要注意,本题中所有无向边都是真实存在的,也就是说,所有待选加油站也需要作为实际的顶点参与Djkstra算法的计算。因此,Djkstra 算法中的顶点编号范围应当是1 ~ (n+ m)。在得到某个加油站的数组d[MAXV]后,需要获取其中最小的元素(即该加油站与居民房的最近距离)及计算所有居民房(1 ~ n)与加油站的平均距离,过程中如果出现某个d[i]大于DS,则说明存在居民房与该待选加油站的距离超过了服务范围,该待选加油站不合格。接下来,如果该最近距离比当前最大的最近距离还大,则更新最大的最近距离;如果最近距离相同,则更新最小的平均距离。

注意点

本题是要使最近距离最大,因此定义存放最大的最近距离的变量时,其初值必须设为一个较小的数。

const int N=1011;
vector<PII> g[N];
int dist[N];
bool vis[N];
int n,m,k,Ds;

int get(string s)
{
    if(s[0] == 'G') return n+stoi(s.substr(1));
    else return stoi(s);
}

void dijkstra(int st)
{
    memset(dist,0x3f,sizeof dist);
    memset(vis,0,sizeof vis);
    priority_queue<PII,vector<PII>,greater<PII>> heap;
    dist[st]=0;
    heap.push({0,st});

    while(heap.size())
    {
        int t=heap.top().se;
        heap.pop();

        if(vis[t]) continue;
        vis[t]=true;

        for(int i=0;i<g[t].size();i++)
        {
            int j=g[t][i].fi,w=g[t][i].se;
            if(dist[j] > dist[t] + w)
            {
                dist[j]=dist[t]+w;
                heap.push({dist[j],j});
            }
        }
    }
}

int main()
{
    cin>>n>>k>>m>>Ds;

    while(m--)
    {
        string a,b;
        int w;
        cin>>a>>b>>w;
        int ta=get(a),tb=get(b);
        g[ta].pb({tb,w});
        g[tb].pb({ta,w});
    }

    int ans=0;
    int bestdist=0,minsum=INF;
    for(int i=n+1;i<=n+k;i++)
    {
        dijkstra(i);

        bool ok=true;
        for(int j=1;j<=n;j++)
            if(dist[j] > Ds)
            {
                ok=false;
                break;
            }
        if(!ok) continue;

        int mindist=INF;
        int sum=0;
        for(int j=1;j<=n;j++)
        {
            mindist=min(mindist,dist[j]);
            sum+=dist[j];
        }

        if(mindist > bestdist)
        {
            ans=i;
            bestdist=mindist;
            minsum=sum;
        }
        else if(mindist == bestdist && sum < minsum)
        {
            ans=i;
            minsum=sum;
        }
    }

    if(ans == 0) puts("No Solution");
    else
    {
        cout<<'G'<<ans-n<<endl;
        printf("%.1f %.1f\n",(double)bestdist,(double)minsum/n+eps);
    }

    //system("pause");
    return 0;
}
posted @ 2021-03-01 20:26  Dazzling!  阅读(37)  评论(0编辑  收藏  举报