dijkstra最短路径(L3-005 垃圾箱分布 (30 分))

本文探讨了一种基于最短路径算法的垃圾箱选址方案,旨在寻找距离所有居民点既不太远也不太近的理想位置,确保社区卫生的同时兼顾居民便利。通过枚举候选点并运用Dijkstra算法,最终确定了满足特定条件的最佳位置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题链接

L3-005 垃圾箱分布 (30 分)
大家倒垃圾的时候,都希望垃圾箱距离自己比较近,但是谁都不愿意守着垃圾箱住。所以垃圾箱的位置必须选在到所有居民点的最短距离最长的地方,同时还要保证每个居民点都在距离它一个不太远的范围内。

现给定一个居民区的地图,以及若干垃圾箱的候选地点,请你推荐最合适的地点。如果解不唯一,则输出到所有居民点的平均距离最短的那个解。如果这样的解还是不唯一,则输出编号最小的地点。

其中P1和P2是道路两端点的编号,端点可以是居民点,也可以是垃圾箱候选点。Dist是道路的长度,是一个正整数。

输出格式:
首先在第一行输出最佳候选地点的编号。然后在第二行输出该地点到所有居民点的最小距离和平均距离。数字间以空格分隔,保留小数点后1位。如果解不存在,则输出No Solution。

输入样例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
输出样例1:
G1
2.0 3.3
输入样例2:
2 1 2 10
1 G1 9
2 G1 20
输出样例2:
No Solution


分析:
看到这一题的第一想法是最小生成树和dij最短路径,后来想想,题目只要求每一个居民点和垃圾桶相连即可,所以选择最短路径。
之后对每一个垃圾桶选择点都进行dij,在dij数组的最大值不大于ds的情况下,选择dij的数组的最小值最大的,如果最小值一样就选择和最小的。
这一题给我的反思就是:在选择最大最小的时候,有关变量也一定要及时更新,不然会出现很难找到的错误,浪费时间去修改代码。
over


#include<iostream>
#include<string.h>
using namespace std;
const int INF = (1<<30) -2;
int dij[1015];
int way[1015][1015];
int book[1015];
int n, m, k, ds;

int main() {
    fill(way[0], way[0] + 1015 * 1015, INF);
    cin >> n >> m >> k >> ds;
    string s1, s2;
    int key;
    for (int i = 1; i <= k; i++) {
        int num1, num2;
        cin >> s1 >> s2 >> key;
        num1 = s1[0] == 'G' ? (s1[1] - '0' + n) : (s1[0] - '0');
        num2 = s2[0] == 'G' ? (s2[1] - '0' + n) : (s2[0] - '0');
        way[num1][num2] = key;
        way[num2][num1] = key;
    }
    
    int ans_max = -1;
    int ans_id = 0;
    int ans_sum = 0;
    for (int i = 1; i <= m; i++) { //枚举每一个候选点
        //dij部分
        fill(book, book + 1011, 0);
        fill(dij,dij + 1011,INF);
        dij[i + n] = 0;
        for (int j = 1; j <= n + m; j++) {
            int x = 0,minn = INF;
            for (int z = 1; z <= n + m; z++) {
                if (book[z] == 0 && minn > dij[z]) {
                    x = z;
                    minn = dij[z];
                }
            }
            if(x == 0) break;
            book[x] = 1;
            for (int z = 1; z <= n + m; z++) {
                if(book[z] == 1 || way[x][z] == INF) continue;
                dij[z] = min(dij[z], dij[x] + way[x][z]);
            }
        }
        //答案处理部分
        int tmin = INF, tmax = -1,sum = 0;
        for (int j = 1; j <= n; j++) {
            tmin = min(tmin, dij[j]);
            tmax = max(tmax, dij[j]);
            sum += dij[j];
        }
        if(tmax <= ds && tmin > ans_max) { //不太远 不太近
            ans_max = tmin;
            ans_id = i;
            ans_sum = sum;
        } else if(tmax <= ds && tmin == ans_max) { //如果一样进 选择 sum最小的
            if (sum < ans_sum) {
                ans_id = i;
                ans_sum = sum;
            }
        }
    }
    if(ans_id != 0) {
        float ans1 = ans_max * 1.0;
        float ans2 = ans_sum * 1.0 / n + 0.5;
        cout << "G" << ans_id << endl;
        printf("%.1f %.1f", ans1, ans2);
    } else {
        cout << "No Solution";
    }
    return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值