PAT甲级1072

PAT甲级1072

题目大意:给出用户数n(不超过1000),加油站数量m(不超过10),道路k条,加油站的最远供应范围ds。接下来给出k行,代表k条道路,其中G开头的代表加油站,让你选择一个合适的加油站,要求如下:
1、所有用户都必须在该加油站到该用户最短路径所能达到的范围内,即加油站到该用户的最短路径不能超过加油站的供应范围;
2、选择加油站到各个用户最短路径中路径最短的那条,该路径作为第一参照应尽可能的大;
3、如果碰到第一参照相同的情况下,则需要求出该加油站到各个用户的平均距离,该平均距离应尽可能的小,此为第二参照;
4、若第二参照也相同则按加油站编号从小到大的顺序选择序号最小的一个;
5、若不存在这样的加油站则输出No Solution

Dijkstra模拟最短路径的问题,可以多开辟几个数组记录平均距离以及最短距离,用户题目说了1~n,所以加油站可以设置为 n+1~n+m,若是碰到不满足题意的加油站则提前跳出。这里题目样例输出的是3.3,实际上平均距离是3.25,所以应该是四舍五入,但是博主四舍五入后第四个测试点不通过,直接按1位小数输出反而能过,可能是bug吧。(这里path是记录路径用的,但是这题没用到可以忽略)

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#define MAXN 1020
#define INF 100000000
using namespace std;

int n,m,k,ds;
bool visit[MAXN];
int road[MAXN][MAXN],dis[MAXN][MAXN];
double average[MAXN];
vector<int> path[MAXN];
void init(){
	fill(visit+1,visit+n+m+1,false);
	for(int i=1;i<=n+m;i++)
		fill(road[i]+1,road[i]+n+m+1,INF);
	for(int i=n+1;i<=n+m;i++)
		fill(dis[i]+1,dis[i]+n+m+1,INF);
}
void Dijkstra(int index){
	fill(visit+1,visit+n+m+1,false);
	dis[index][index]=0;
	for(int i=1;i<=m+n;i++){
		int u=-1,min=INF;
		for(int j=1;j<=m+n;j++)
			if(!visit[j]&&dis[index][j]<min)
				u=j,min=dis[index][j];
		if(u==-1) return ;
		visit[u]=true;
		for(int j=1;j<=m+n;j++){
			if(!visit[j]&&road[u][j]<INF&&dis[index][u]+road[u][j]<=dis[index][j]){
				if(dis[index][u]+road[u][j]<dis[index][j]){
					dis[index][j]=dis[index][u]+road[u][j];
					path[j].clear();
					path[j].push_back(u);
				}else{
					path[j].push_back(u);
				}
			}
		}
	}
}
void ave(int index){
	double sum=0;
	for(int i=1;i<=n;i++)
		sum+=dis[index][i];
	average[index]=sum/n;
}
int string_to_int(string a){
	int toint;
	if(a[0]!='G') toint=stoi(a);
	else{
		toint=n+stoi(a.substr(1,a.length()-1));
	}
	return toint;
}
int main(){
	int h1,h2,length,minDis=-1,target=0;
	string house1,house2;
	scanf("%d%d%d%d",&n,&m,&k,&ds);
	init();
	for(int i=0;i<k;i++){	//前n个存放住户,后n+m个存放加油站
		cin>>house1>>house2;
		h1=string_to_int(house1);
		h2=string_to_int(house2);
		scanf("%d",&length);
		road[h1][h2]=length;
		road[h2][h1]=length;
	}
	for(int i=n+1;i<=n+m;i++){
		Dijkstra(i);
		ave(i);
		int tmpDis=INF;
		bool canBuilt=true;
		for(int j=1;j<=n;j++){
			if(dis[i][j]>ds){
				canBuilt=false;
				break;
			}
			if(dis[i][j]<tmpDis) tmpDis=dis[i][j];
		}
		if(canBuilt){
			if(tmpDis>minDis) minDis=tmpDis,target=i;
			else if(tmpDis==minDis){
				if(average[i]<average[target]){
					target=i;
				}else if(average[i]==average[target]){
					if(i<target) target=i;
				}
			}
		}
		// for(int j=1;j<=n;j++)
		// 	printf("%d ",dis[i][j]);
		// printf("\n");
	}
	if(minDis==-1) printf("No Solution");
	else{
		printf("G%d\n",target-n);
		printf("%.1f %.1f",(double)minDis,average[target]);
	}
	system("pause");
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值