L3-005 垃圾箱分布 (30分)

L3-005 垃圾箱分布 (30分)

大家倒垃圾的时候,都希望垃圾箱距离自己比较近,但是谁都不愿意守着垃圾箱住。所以垃圾箱的位置必须选在到所有居民点的最短距离最长的地方,同时还要保证每个居民点都在距离它一个不太远的范围内。
现给定一个居民区的地图,以及若干垃圾箱的候选地点,请你推荐最合适的地点。如果解不唯一,则输出到所有居民点的平均距离最短的那个解。如果这样的解还是不唯一,则输出编号最小的地点。

输入格式
输入第一行给出4个正整数:N(≤1000​​ )是居民点的个数;M(≤10)是垃圾箱候选地点的个数;K(≤1000-​​ )是居民点和垃圾箱候选地点之间的道路的条数;D​​是居民点与垃圾箱之间不能超过的最大距离。所有的居民点从1到N编号,所有的垃圾箱候选地点从G1到GM编号。
随后K行,每行按下列格式描述一条道路:
P1 P2 Dist
其中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

还有题目的有些表达有点坑
这道题有一点坑,就是他的第一个样例的输出是错的,导致我调试了半天,应该是:

G1
2.0 3.2
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <vector>
#include <stack>
#include <queue>
#include <cmath>
#include <string.h>
using namespace std;
#define N 1020
using ll=long long;
int n,m,k,head[N],cnt;
ll c,d;
char from[20],to[20];
bool vis[N];//标记某个点是否访问过
int toint(char* s){
    int ans=0;
    while(*s) ans=ans*10+*s-'0',s++;
    return ans; 
}
int getindex(char* s){
    //重新映射垃圾箱和居民区的地址
    //G1-Gm映射为[1,m]
    //居民点1-n映射为[1+m,1+m+n]
    if(s[0]=='G') return toint(s+1);
    else return m+toint(s);
}
struct node{
    //存储边信息
    int to;
    //到达点
    int next;
    //下一个节点
    ll d;
    //距离
}e[20005];
void add(int from,int to){
    //邻接表表示
    e[++cnt].to=to;
    e[cnt].next=head[from];
    e[cnt].d=c;
    head[from]=cnt;

    e[++cnt].to=from;
    e[cnt].next=head[to];
    e[cnt].d=c;
    head[to]=cnt;
}
bool isperson(int i){
    //是否是一个居民点
    return i>m;
}

struct info{
    int i;
    ll d;
};
struct cmp{
    bool operator ()(info&a,info&b){
        return a.d>b.d;
    }
};
ll total,min_dis;
bool bfs(int p){
    memset(vis,0,N);
    priority_queue<info,vector<info>,cmp> Q;
    //利用堆来加快迪杰斯特拉的速度
    Q.push({p,0});
    info cur;
    total=0;
    min_dis=-1;
    while(!Q.empty()){
        cur=Q.top();
        Q.pop();
        if(vis[cur.i]) continue;
        vis[cur.i]=true;
        if(isperson(cur.i)){
            //访问到一个居民点
            if(min_dis==-1) min_dis=cur.d;
            //更新垃圾站p到所有居民点中的最小距离
            total+=cur.d;
            //总距离
            if(cur.d>d) return false;
            //发现p到cur.i的距离超过了题目中d的限制
        }
        for(int i=head[cur.i];i;i=e[i].next){
            //访问与cur.i相邻的点
            if(vis[e[i].to]) continue;
            Q.push({e[i].to,cur.d+e[i].d});
        }
    }
    for(int i=m+1;i<=n+m;i++) if(!vis[i]) return false;
    //检查是否有居民点未被访问到
    return true;
}
int main(){
    scanf("%d %d %d %lld\n",&n,&m,&k,&d);
    for(int i=0;i<k;i++){
        scanf("%s %s %lld\n",from,to,&c);
        add(getindex(from),getindex(to));
        
    }
    int ans_index=-1;//垃圾箱编号答案
    ll ans_min_dis,ans_total;//到所有居民地中的最小距离,到所有居民地总距离
    for(int i=1;i<=m;i++){
        if(!bfs(i)) continue;
        if(ans_index==-1 || min_dis>ans_min_dis || (min_dis==ans_min_dis && total<ans_total) || (min_dis==ans_min_dis && total==ans_total && i<ans_index)){
            ans_index=i;
            ans_min_dis=min_dis;
            ans_total=total;
        }
    }
    if(ans_index==-1){
        printf("No Solution\n");
    }else{
        printf("G%d\n",ans_index);
        printf("%.1lf %.1lf\n",(double)ans_min_dis,(double)ans_total/n);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值