PTA——L3-005 垃圾箱分布(Dijkstra)

文章介绍了如何利用Dijkstra算法在一个给定的居民区地图上找到满足所有居民点需求且平均距离最短的垃圾箱位置,通过构建图并进行优化搜索来解决此最优化问题。
摘要由CSDN通过智能技术生成

一、题目

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;    
}
/*

*/
  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值