题目:一个城市有i个小镇,其中有一些小镇建有消防站,现在想增加1个消防站,
使得所有小镇到最近的消防站的距离中的最大值最小。
分析:图论,最短路。利用spfa算法可以高效解决本问题。
首先,利用已有的消防站,计算多源最短路径,储存在集合dist中;
然后,枚举所有顶点,计算单元最短路,存储在集合newd中,则得到新的多元最短路集合S;
他的元素为对应newd与dist元素的最小值,即S = { min(dist(i),newd(i))};
(如果,一个新的消防站可以更新之前消防站的最短路,则这组解一定在这个点的单元最短路中)
最后,计算出每种情况的最远距离,去最小值即可。
说明:注意数据读入格式,有点恶心。
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
using namespace std;
//link_define
typedef struct enode
{
int point;
int length;
enode* next;
}edge;
edge *H[505];
edge E[100001];
int e_count;
void link_initial()
{
e_count = 0;
memset(H, 0, sizeof(H));
memset(E, 0, sizeof(E));
}
void link_add(int a, int b, int c)
{
E[e_count].point = b;
E[e_count].length = c;
E[e_count].next = H[a];
H[a] = &E[e_count ++];
}
//link_end
int fire[505],dist[505],newd[505];
int visit[505],stack[505];
void spfa(int s, int *path)
{
int save = 0;
stack[save ++] = s;
visit[s] = 1;
while (save) {
int now = stack[-- save];
for (edge *p = H[now] ; p ; p = p->next)
if (path[p->point] > path[now] + p->length) {
path[p->point] = path[now] + p->length;
if (!visit[p->point]) {
visit[p->point] = 1;
stack[save ++] = p->point;
}
}
visit[now] = 0;
}
}
int main()
{
int t,n,m,a,b,c;
char buf[255];
while (~scanf("%d",&t))
while (t --) {
scanf("%d%d",&n,&m);
getchar();
for (int i = 1 ; i <= n ; ++ i) {
scanf("%d",&fire[i]);
getchar();
}
link_initial();
while (gets(buf) && strlen(buf)) {
sscanf(buf, "%d%d%d",&a,&b,&c);
link_add(a, b, c);
link_add(b, a ,c);
}
//处理原有的消防站
for (int i = 1 ; i <= m ; ++ i) {
dist[i] = 0x7ffffff;
visit[i] = 0;
}
for (int i = 1 ; i <= n ; ++ i) {
dist[fire[i]] = 0;
spfa(fire[i], dist);
}
int Min = 0x7ffffff,Spa = 1;
for (int i = 1 ; i <= m ; ++ i) {
for (int j = 1 ; j <= m ; ++ j) {
newd[j] = 0x7ffffff;
visit[j] = 0;
}
newd[i] = 0;
spfa(i, newd);
int Max = 0;
for (int j = 1 ; j <= m ; ++ j)
Max = max(Max, min(dist[j], newd[j]));
if (Max < Min) {
Min = Max;
Spa = i;
}
}
printf("%d\n",Spa);
if (t) printf("\n");
}
return 0;
}