一、题目
L3-005 垃圾箱分布
大家倒垃圾的时候,都希望垃圾箱距离自己比较近,但是谁都不愿意守着垃圾箱住。所以垃圾箱的位置必须选在到所有居民点的最短距离最长的地方,同时还要保证每个居民点都在距离它一个不太远的范围内。
现给定一个居民区的地图,以及若干垃圾箱的候选地点,请你推荐最合适的地点。如果解不唯一,则输出到所有居民点的平均距离最短的那个解。如果这样的解还是不唯一,则输出编号最小的地点。
二、题解
基本思路:
- 我们要求出到所有居民点最短距离最长的垃圾箱的位置,很明显这是一道最短路的题,我们枚举每个垃圾箱,找出垃圾箱距离居民点的最短距离。最后求出最长的最短距离最长的那个即可!
- 我们可以给居民点和垃圾箱重新编号,这样更方便建图,不然垃圾箱的编号带着字符。
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl "\n"
#define int long long
#define fi first
#define se second
const int N = 1e4+10, INF = 0x3f3f3f3f;
typedef pair<int,int> PII;
int n,m,K,Ds; //n个居民点,m个垃圾箱,可以看作n+m个点!
unordered_map<string,int> mp; //给点编号
vector<pair<int,int>> e[N]; //邻接表存图
int dist[N]; //最短路
struct node{
int st; //最短距离
double avedist; //平均最短距离
int num; //编号
bool operator < (const node &A){
if(st!=A.st) return st>A.st; //1.最短距离最大
if(avedist!=A.avedist) return avedist<A.avedist; //2.到所有居民点的平均距离最短
return num<A.num; //3.编号最小
}
};
vector<node> ans; //记录答案
void dijkstra(int s){ //堆优化
priority_queue<PII,vector<PII>,greater<PII>> q; //小根堆
bool vis[N]; //有没有确定最短路
memset(dist,INF,sizeof(dist));
memset(vis,false,sizeof(vis));
dist[s]=0; //源点到自己距离为0
q.push({dist[s],s});
while(q.size()){
auto t=q.top(); q.pop();
int u=t.se; //该点编号
if(vis[u]) continue; //已经确定最短路了,跳过
vis[u]=1; //确定最短路
for(auto i:e[u]){ //更新,松弛
int v=i.fi,w=i.se; //终点,边权
if(dist[u]+w<dist[v]){ //更新
dist[v]=dist[u]+w;
q.push({dist[v],v});
}
}
}
}
void solve() {
cin>>n>>m>>K>>Ds;
//给居民点编号 1~n
for(int i=1;i<=n;i++){
string str=to_string(i);
mp[str]=i;
}
//给垃圾箱编号 n+1~n+1+m
for(int i=1;i<=m;i++){
string str=to_string(i);
str="G"+str;
mp[str]=n+i;
}
//建图,连边
for(int i=1;i<=K;i++){
string s1,s2; int d;
cin>>s1>>s2>>d;
int x=mp[s1],y=mp[s2];
e[x].push_back({y,d});
e[y].push_back({x,d});
}
//求出满足条件的垃圾箱
for(int i=n+1;i<=n+1+m;i++){ //枚举垃圾箱的编号
dijkstra(i); //求出第i号垃圾箱到所有点的最短路径
bool flag=true; //判断垃圾箱符不符合要求
int sum=0,minn=INF; //距离之和,到居民点的最小距离
for(int j=1;j<=n;j++){
if(dist[j]>Ds) flag=false; //居民点与垃圾箱之间超过了最大距离
sum+=dist[j];
if(dist[j]<minn) //更新最短距离
minn=dist[j];
}
if(!flag) continue; //垃圾箱不符合要求
ans.push_back({minn,sum*1.0/n,i}); //记录
}
//输出答案
if(!ans.size()){ //无解!
cout<<"No Solution"<<endl;
return;
}
sort(ans.begin(),ans.end());
int res=ans[0].num;
for(auto i:mp){ //输出垃圾箱编号G几
if(i.se==res){
cout<<i.fi<<endl;
break;
}
}
printf("%.1f %.1f\n",(double)ans[0].st,ans[0].avedist);
}
signed main() {
// IOS;
int T=1;
// cin>>T;
while(T--) {
solve();
}
return 0;
}
/*
*/