pat甲级(中等题) 加油站

  acwing:1558. 加油站

加油站的建造位置必须使加油站与距离它最近的房屋的距离尽可能远。

与此同时,它还必须保证所有房屋都在其服务范围内。

现在,给出了城市地图和加油站的几个候选位置,请你提供最佳建议。

如果有多个解决方案,请输出选取位置与所有房屋的平均距离最小的解决方案。

如果这样的解决方案仍然不是唯一的,请输出选取位置编号最小的解决方案。

输入格式

第一行包含四个整数 N,房屋总数,M,加油站的候选位置总数,K,连接房屋或加油站的道路总数,Ds 加油站的最大服务范围。

所有房屋的编号从 1到 N,所有加油站侯选位置编号从 G1 到 GM

接下来 K 行,每行格式如下:

P1 P2 Dist

其中,P1 和 P2 表示一条 无向 道路连接的两个房屋或加油站侯选位置的编号,Dist 是道路长度,这是一个整数。

输出格式

第一行输出所选位置的编号。

第二行输出加油站与距离其最近的房屋之间的距离以及与所有房屋之间的平均距离,精确到小数后一位

如果解决方案不存在,则输出 No Solution

 题解:

普通的dijkstra,但是注意精度(加1e-8才能过)。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 1020, M = 20010;
typedef pair<int, int>PII;
int h[N], e[M], ne[M], w[M], idx;
int dis[N];
int n, m, k, ds;
bool st[N];
int sum[12];
void add(int a, int b, int c) {
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
void dijk(int u)
{
    memset(dis, 0x3f, sizeof(dis));
    memset(st, false, sizeof(st));
    priority_queue<PII, vector<PII>, greater<PII>>q;
    q.push({ 0,u });
    dis[u] = 0;
    while (q.size()) {
        auto t = q.top();
        q.pop();
        int v = t.second;
        if (st[v]) {
            continue;
        }
        st[v] = true;
        for (int i = h[v];i != -1;i = ne[i]) {
            int j = e[i];
            if (dis[j] > dis[v] + w[i]) {
                dis[j] = dis[v] + w[i];
                q.push({ dis[j],j });
            }
        }
    }
}
void solve()
{
    memset(h, -1, sizeof(h));
    cin >> n >> m >> k >> ds;
    for (int i = 1;i <= k;i++) {
        string s1, s2,s;
        int a, b;
        int c;
        cin >> s1 >> s2 >> c;
        if (s1[0] == 'G') {
            s = s1.substr(1);
            a = atoi(s.c_str()) + 1000;
        }
        else {
            a = atoi(s1.c_str()) ;
        }
        if (s2[0] == 'G') {
            s = s2.substr(1);
            b = atoi(s.c_str()) + 1000;
        }
        else {
            b = atoi(s2.c_str()) ;
        }
        add(a, b, c);
        add(b, a, c);
    }
    bool Flag = 0;
    string s_ans;
    double av_ans = 0;
    double ans = 0;
    int th = 1;
    int ht = 0;
    do {
        dijk(th + 1000);
        /*for(int i=1;i<=n;i++){
            printf("%d ",dis[i]);
        }printf("\n");*/
        bool flag = 0;
        int anss = 5001;
        int Sum = 0;
        for (int i = 1;i <= n;i++) {
            Sum += dis[i];
            anss = min(anss, dis[i]);
            if (dis[i] > ds) {
                flag = 1;
                break;
            }
        }
        if (flag) {
            continue;
        }
        sum[ht] = Sum;
        ht++;
        //printf("%d\n",sum[ht-1]);
        if (ans < anss) {
            ans = anss;
            av_ans = (1.0) * sum[ht - 1] / n;
            s_ans[0] = 'G', s_ans[1] = th + 48;
            Flag = 1;
        }
        else if (ans == anss) {
            if (av_ans > (1.0) * sum[ht - 1] / n) {
                av_ans = (1.0) * sum[ht - 1] / n;
                s_ans[0] = 'G', s_ans[1] = th + 48;
                Flag = 1;
            }
        }
    } while (th++, th <= m);
    //av_ans=(av_ans+0.05)*10;
    //av_ans/=10;
    if (Flag) {
        printf("%s\n", s_ans.c_str());
        printf("%.1lf %.1lf", ans, av_ans + 1e-8);
    }
    else {
        cout << "No Solution" << endl;
    }

}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int t = 1;
    while (t--) {
        solve();
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值