题目:一个城市有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; }
时间: 2024-11-08 12:56:12