这题比较难,考察最短路径,加了很多复杂的条件。
第一步,读懂题意
首先题意需要读懂,候选加油站需要满足以下条件:
1、加油站离每个住宅的最短距离要在服务范围内;
2、针对每个候选加油站,求出这个加油站到每个住宅的最短距离,这些最短距离中最小的那一个值,也就是离整个住宅区的最短距离,越大越好;
3、如果有多个这样的候选加油站,那么针对每个候选加油站,求这个加油站到每个住宅的最短距离的和,最短距离和越小越好;
4、如果有多个这样的候选加油站,那么加油站的编号越小越好。
因此,解题思路是:
1、输入数据;
2、用Floyd算法求出两点之间的最短距离;
3、逐个判断哪个加油站是有效最优解;
4、按要求输出结果。
第二步,处理输入
输入有字符有数字,并且还有干扰输出,比如:
1、同一个起点和终点间有两条路,这时候只保存最短的那条;
2、起点和终点是同一个位置,忽略;
3、用字符数组接收编号,如果开头是G,那么为加油站,将它转换成数字N+i(N是住宅的总数,i是该加油站的数字编号)。
第三步,选择算法
大致有两种算法:
1、将问题看作全源最短路径,用Floyd算法求得每两点间的最短距离,从而找出最佳候选位置。
Floyd算法的时间复杂度大约是三次方,最后一个用例会超时。
2、改变思路,将问题看作单源最短路径,针对每个加油站都做一次单源最短路径,用Dijkstra算法,时间复杂度大约是二次方,而加油站候选位置不超过10个,因此仍然是二次方复杂度。问题解决。
最短路径算法是很重要的,通过这题可以再次回顾一下两种最短路径算法。网上的博客或多或少不够清晰、完整,还缺少证明的过程,不利于记忆学习。对于这些经典的算法,推荐阅读纸质书籍,比如《算法导论》第24/25章。
AC代码
#include<stdio.h>
#include<vector>
#include<queue>
#include<functional>
#include<iterator>
using namespace std;
struct E
{
int next;
int c;
};
vector<E> edge[1011];
bool mark[1011];
int dis[1011];
int main()
{
int N, M, K, D;
scanf("%d%d%d%d", &N, &M, &K, &D);
char start[5], end[5];
int from, to;
int d;
for (int i = 0; i < K; i++)
{
scanf("%s%s%d", start, end, &d);
if (start[0] != 'G')
{
from = atoi(start);
}
else
{
from = N + atoi(&start[1]);
}
if (end[0] != 'G')
{
to = atoi(end);
}
else
{
to = N + atoi(&end[1]);
}
if (from == to)
{
continue;
}
bool flag = true;
for (int j = 0; j < edge[from].size(); j++)
{
if (edge[from][j].next == to)
{
flag = false;
if (d < edge[from][j].c)
{
edge[from][j].c = d;
}
break;
}
}
if (!flag)
{
continue;
}
E e;
e.next = to;
e.c = d;
edge[from].push_back(e);
e.next = from;
edge[to].push_back(e);
}
int bestStation = -1;
int bestSum = 1000000;
int bestMin = 0;
for (int i = N + 1; i <= M + N; i++)
{
for (int j = 1; j <= M + N; j++)
{
dis[j] = -1;
mark[j] = false;
}
dis[i] = 0;
mark[i] = true;
int newP = i;
for (int j = 1; j < M + N; j++)
{
for (int k = 0; k < edge[newP].size(); k++)
{
int t = edge[newP][k].next;
int c = edge[newP][k].c;
if (mark[t] == true)
{
continue;
}
if (dis[t] == -1 || dis[t] > dis[newP] + c)
{
dis[t] = dis[newP] + c;
}
}
int min = 100000;
for (int k = 1; k <= M + N; k++)
{
if (mark[k] == true || dis[k] == -1)
{
continue;
}
if (dis[k] < min)
{
min = dis[k];
newP = k;
}
}
mark[newP] = true;
}
int min = 100000, sum = 0;
bool flag = true;
for (int j = 1; j <= N; j++)
{
if (dis[j] > D || dis[j] == -1)
{
flag = false;
break;
}
sum += dis[j];
if (dis[j] < min)
{
min = dis[j];
}
}
if (flag && ((min > bestMin) || (min == bestMin && sum < bestSum)))
{
bestMin = min;
bestStation = i;
bestSum = sum;
}
}
if (bestStation == -1)
{
printf("No Solution\n");
}
else
{
printf("G%d\n%.1f %.1f\n", bestStation - N, (float)bestMin, (float)bestSum / N);
}
return 0;
}
来源:https://blog.csdn.net/qq_39115541/article/details/100165785