题目大意:给出一张图的顶点和边的信息。顶点1~N是居民区,N+1~N+M是加油站,每个加油站的覆盖范围是DS。现在要求找到符合以下条件的加油站:到居民区的最短距离尽可能大,但必须保证每个居民区都能覆盖。如果这样的加油站不止一个(意为到居民区的最短距离最大的加油站不止一个),选取到居民区的平均距离最小的那个。如果这样的加油站还是不止一个,选取编号最小的那个。
总体思路是,对于每一个加油站,进行一次dijkstra算法,得到该加油站到所有居民区的最短距离,然后根据要求进行判断:①能否覆盖所有居民区?即所有最短距离中的最大值应<=DS。② 是否离居民区尽可能远?即所有最短距离中的最小值应当比记录的最短距离的最小值要大。③ 如果和记录的最短距离最小值相等,那么判断到所有居民区的平均距离是否是最小的。④ 选取编号最小的那个,这一条因为遍历顺序是 N+1 ~ N+M, 只要控制更新解的条件是满足前三条,最后输出的解一定是编号最小的。
PAT上的测试数据似乎坑不多,但是牛客网上本题的测试数据有坑点,表现在可能出现 G[A] G[A] 10 或者 G[A] G[B] 20; G[A] G[B] 30; 这样的数据。对应措施是:输入时,首先要判断这两个顶点是否是同一个点,不是同一个点的情况下才能存储。其次,这两个点如果重复出现过,判断它们之间的距离是否已经比这次的输入距离要小,如果是,就忽略这次输入,即重复输入的顶点对,它们的距离取最小的那个。
最后还有一个坑点,题目要求精确到1位小数,但是从给出的示例的输出结果来看,3.25被输出了3.3,应当是四舍五入。如果用“%.1f",实现的是”四舍六入五成双“,即输出3.2。所以我用的round函数实现的四舍五入,round(double* 10) / 10。但实际上使用"%.1f"也能过。非常奇怪,可能测试点里没有第二位小数是5的情形吧。
AC代码:
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 1100;
const int INF = 0x7FFFFFFF;
int Graph[MAXN][MAXN];
vector G[MAXN];
int d[MAXN] = {0};
bool visited[MAXN] = {false};
void dijkstra(int s, int N, int houseNum, int &minDis, int &maxDis, double &avgDis)
{
fill(d, d + MAXN, INF);
fill(visited, visited + MAXN, 0);
d[s] = 0;
for (int i = 1; i <= N; ++i)
{
int u = -1, min = INF;
for (int j = 1; j <= N; ++j)
{
if(!visited[j] && d[j] < min)
{
min = d[j];
u = j;
}
}
if(u == -1) return;
visited[u] = true;
for (int k = 0; k < G[u].size(); ++k)
{
int v = G[u][k];
if(!visited[v] && d[v] > d[u] + Graph[u][v])
d[v] = d[u] + Graph[u][v];
}
}
sort(&d[1], &d[houseNum + 1]);
minDis = d[1];
maxDis = d[houseNum];
for (int i = 1; i <= houseNum; ++i)
avgDis += d[i] * 1.0 / houseNum;
}
int main()
{
fill(Graph[0], Graph[0] + MAXN * MAXN, INF);
int N, M, K, DS;
scanf("%d%d%d%d", &N, &M, &K, &DS);
for (int i = 0; i < K; ++i)
{
char s1[10], s2[10];
int u, v, dis;
scanf("%s %s %d", s1, s2, &dis);
string str1 = string(s1), str2 = string(s2);
if(str1[0] == 'G') u = N + stoi(str1.substr(1, str1.size() - 1));
else u = stoi(str1);
if(str2[0] == 'G') v = N + stoi(str2.substr(1, str2.size() - 1));
else v = stoi(str2);
if(u != v)
{
G[u].push_back(v);
G[v].push_back(u);
if(dis < Graph[u][v]) Graph[u][v] = Graph[v][u] = dis;
}
}
int index = -1, minimumDis = 0;
double minAvgDis = 1e10;
for (int i = N + 1; i <= N + M; ++i)
{
int minDis = 0, maxDis = INF;
double avgDis = 0;
dijkstra(i, N + M, N, minDis, maxDis, avgDis);
if(maxDis <= DS)
{
if(minDis > minimumDis)
{
index = i;
minimumDis = minDis;
minAvgDis = avgDis;
}
else if(minDis == minimumDis && avgDis < minAvgDis)
{
index = i;
minAvgDis = avgDis;
}
}
}
if(index > -1) printf("G%d\n%.1f %.1f", index - N, minimumDis * 1.0, minAvgDis);
else printf("No Solution");
return 0;
}