PAT A1072 Gas Station(30)

本文介绍了一个基于最短路径算法的加油站选址问题解决方案。该方案通过多次运行Dijkstra算法确定最佳加油站位置,确保服务范围内覆盖所有居民区,并以最小距离和平均距离作为评估标准。

题意

  • 这个题读起来有点烦,是这样的,首先有N个居民房和M个加油站,每个加油站都对应着一个最小距离和平均距离,加油站的最小距离是指从他到其他所有居民房的最短路径的最小值(从N条最短路径里面选),现在让你选择一个加油站,首先他到所有居民房的最短路径均不能大于服务范围(每个加油站都一样),其次他的最小距离在所有加油站的最小距离中最大(从M个加油站中选),若不唯一,选择平均距离最小的,若再不唯一,选择编号最小的。若没有一个加油站能服务到所有居民房,那么输出No Solution

注意

  1. 因为算每个加油站的最小距离和平均距离需要知道最短路径长度,所以每个加油站都要来一遍dijkstra,每算出来一个加油站到一个居民房的最短路径(S集新元素)就更新这个加油站的最小距离和平均距离,同时也要判断是否小等于服务范围,不然这个加油站的dijkstra直接结束。
  2. 把平均距离先按照距离和处理,最后再除。
  3. 把每个加油站的信息算完以后,再在加油站之间比这俩数,不满足服务范围的加油站不用考虑。
  4. 加油站编号还要处理一下。

代码

#include <iostream>
#include <algorithm>
#include <climits>
#include <string>  
using namespace std;

const int Nmax = 1011;
int N, M, K, Ds;
int road[Nmax][Nmax];

int dist[Nmax];
bool S[Nmax];

bool isM[11];
int minRoad[11];
int avgRoad[11];

void DIJKSTRA()
{
	fill(isM, isM + 11, false);
	fill(minRoad, minRoad + 11, INT_MAX);
	fill(avgRoad, avgRoad + 11, 0);
	for (int i = 1; i <= M; i++)
	{
		fill(S, S + Nmax, false);
		fill(dist, dist + Nmax, INT_MAX);
		dist[i + N] = 0;
		for (int k = 1; k <= N + M; k++)
		{
			int min = INT_MAX;
			int u;
			for (int j = 1; j <= N + M; j++)
			{
				if (!S[j] && dist[j] < min)
				{
					min = dist[j];
					u = j;
				}
			}
			if (dist[u] > Ds && u <= N)
			{
				isM[i] = true;                 //////
				break;
			}
			S[u] = true;
			if (u <= N)
			{
				avgRoad[i] += dist[u];
				if (dist[u] < minRoad[i])
					minRoad[i] = dist[u];
			}
			for (int j = 1; j <= N + M; j++)
			{
				if (!S[j] && road[u][j] != INT_MAX)
				{
					if (dist[u] + road[u][j] < dist[j])
					{
						dist[j] = dist[u] + road[u][j];
					}
				}
			}
		}
	}
}

void select()
{
	int opt = 0;
	int max = -1;
	for (int i = 1; i <= M; i++)
	{
		if (!isM[i])
		{
			if (minRoad[i] > max)
			{
				max = minRoad[i];
				opt = i;
			}
			else if (minRoad[i] == max && avgRoad[i] < avgRoad[opt])
			{
				opt = i;
			}
		}
	}
	if (opt == 0)
	{
		cout << "No Solution";
		return;
	}
	double minR, avgR;
	minR = minRoad[opt];
	avgR = (double)(avgRoad[opt]) / (double)(N);
	cout << "G" << opt << endl;
	printf("%.1f %.1f", minR, avgR);
}

int main()
{
	cin >> N >> M >> K >> Ds;
	string r1, r2;
	int r3, r4;
	fill(road[0], road[0] + Nmax*Nmax, INT_MAX);
	for (int i = 0; i < K; i++)
	{
		cin >> r1 >> r2;
		if (r1[0] == 'G')
			r3 = atoi(r1.substr(1, r1.size() - 1).c_str()) + N;
		else
			r3 = atoi(r1.c_str());

		if (r2[0] == 'G')
			r4 = atoi(r2.substr(1, r2.size() - 1).c_str()) + N;
		else
			r4 = atoi(r2.c_str());

		cin >> road[r3][r4];
		road[r4][r3] = road[r3][r4];
	}
	DIJKSTRA();
	select();

    return 0;
}
### 关于 PAT 乙级 1072 题目的 Java 实现与解题思路 对于PAT乙级1072题目,虽然未直接提供该具体编号的解析,但从相似类型的编程挑战来看,可以推测此题可能涉及字符串处理或特定算法的应用。为了更好地理解并解决这个问题,下面介绍一种通用方法来应对这类竞赛题目。 #### 数据结构的选择 考虑到效率问题,在处理此类问题时通常会选择哈希表(HashMap)作为主要的数据存储工具[^2]。这有助于快速查找和更新键值对关系,从而简化逻辑判断过程。 #### 输入输出管理 首先应当仔细阅读题目要求,确保能够正确接收输入参数,并按照指定格式输出结果。例如,当遇到需要验证某些条件的情况时,应该严格按照给定的标准进行校验。 #### 主体逻辑构建 假设目标是要检查某个序列是否符合特定模式,则可以通过遍历整个列表来进行逐项对比;如果是关于数值转换的任务,则需注意边界情况以及溢出可能性。针对不同场景下的需求调整核心运算部分的设计。 #### 错误预防机制 编写代码过程中务必加入必要的异常捕获语句,防止因非法输入而导致程序崩溃。同时也要重视测试环节,利用多种样例反复检验最终版本的功能完整性。 ```java import java.util.*; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); // 假设此处为具体的业务逻辑实现 System.out.println("答案正确"); } } ``` 由于缺乏确切的题目描述,上述框架仅作为一个模板展示。实际操作中应依据官方文档所提供的细节进一步完善各个功能模块。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值