PAT 1072. Gas Station (30) dijkstra应用

本文介绍了一个基于Dijkstra算法解决最优加油站选址的问题。目标是在满足指定距离限制条件下,找到距离所有居民区最小距离最大的加油站,若最小距离相同则优选平均距离最小且编号最小的加油站。

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

/*************************
题意:
给出一个图
里面有居民区1-N,也有加油站G1-GN
选择一个加油站
要求该加油站 到居民区的最小距离  最大,并且各距离都在ds范围内
如果最小距离相同, 则要求 到各居民区的平均距离 最小
还相等,则要求序号最小
************************/

/***********************
简单的Dijkstra
以每个加油站做起点,做一次dijkstra
然后检查上述的4个条件去选择一个最合适的加油站
写的时候要谨慎,因为dijstra这种非常容易写错。

注意点:
	1. 注意居民区序号是1-N, 加油站序号是G1-GM
	2. 故我们可以把加油站的序号设为 N+i,i是Gi中的i,即可以少开一些数组
*************************/
/***********************
笔记:
*********************/
#include<iostream>
#include<stdio.h>
#include<string>
#include<vector>
#include<queue>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<stack>
#include<map>
#include<set>
#include<unordered_map>
using namespace std;
#define M 1200
#define INF 0x7ffffff


struct Ans{
	int index;
	int mindis;
	double avgdis;
};

bool cmp(Ans a,Ans b){
	if(a.mindis > b.mindis)
		return true;
	else if(a.mindis == b.mindis){
		if(a.avgdis < b.avgdis)
			return true;
		else if(a.avgdis == b.avgdis)
			return a.index <b.index;
		else return false;
	}
	else return false;
}

vector<Ans> ans;


int dis[M][M];
int n,m,k,ds;
void dijk(int s){
	int d[M], v[M], i, j;
	for(i = 1; i <=n + m;i++){
		d[i] = INF;
		v[i] = 0;
	}
	d[s] = 0;

	int dismin,select;
	for(i = 1;i <= n + m;i++){
		dismin = INF;
		for(j = 1; j <= n + m; j++){
			if(!v[j] && d[j] < dismin){
				dismin = d[j];
				select = j;
			}
		}
		if(dismin == INF )  
			break;
		v[select] = 1;
		for(j = 1;j <= n + m; j++){
			if(!v[j] && d[select] + dis[select][j] < d[j]){
				d[j] = d[select] + dis[select][j];
			}
		}
	}

	dismin = INF;
	int sum=0;
	for(i = 1;i <= n; i++){
		if(d[i] > ds)
			break;
		if(d[i]<dismin){
			dismin = d[i];
		}
		sum += d[i];
	}
	Ans a;
	if(i == n+1){
		a.avgdis = double(sum)/double(n);
		a.index = s-n;
		a.mindis = dismin;
		ans.push_back(a);
	}
}

int main(){
	int i;
	string strs,stre;
	int s,e,d,j;
	scanf("%d%d%d%d",&n,&m,&k,&ds);
	
	for(i=1;i<=n+m;i++)
		for(j=1;j<=n+m;j++){
			if(i != j)
				dis[i][j] = INF;
			else dis[i][j] = 0;
		}

	for(i=0;i<k;i++){
		cin>>strs>>stre>>d;
		if(strs[0] == 'G'){
			s = n + atoi(strs.substr(1).c_str()); 
		}
		else s = atoi(strs.c_str()); 
		if(stre[0] == 'G'){
			e = n + atoi(stre.substr(1).c_str());
		}
		else e = atoi(stre.c_str());
		if(d < dis[s][e]){
			dis[s][e] = d;
			dis[e][s] = d;
		}
	}

	for(i = n + 1; i <= n + m;i++){
		s = i;
		dijk(s);
	}

	if(ans.size() == 0){
		cout<<"No Solution"<<endl;
	}
	else{
		sort(ans.begin(),ans.end(),cmp);
		printf("G%d\n%.1lf %.1lf\n",ans[0].index,double(ans[0].mindis),ans[0].avgdis);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值