题目描述:某个城市的消防任务由一些消防站承担。有些居民抱怨离他们家最近的消防站距离太远了,所以市政府决定在修建一个新的消防站。试选择消防站的位置,以减小这些居民离家最近的消防站的距离。
思路:其实这题是一个最短路径的枚举,用dist[i]表示i号路口距离最近的消防站的距离,先求出已经存在的消防站的最短路径,更新dist数组,然后枚举剩下的路口,更新dist求出最小值。此题可以用floyd先求出所有的最短路径,然后再去更新比较,不过效率不高用时1797ms。用优化的spfa只需79ms.
floyd代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
const int inf = 1000000000;
const int maxn = 505;
int f,n;
bool sta[maxn];//消防站
int edge[maxn][maxn];
int dist[maxn];
bool input(){
if(scanf("%d%d",&f,&n) != 2) return false;
int x;
for(int i = 1; i <= n; i++) sta[i] = false;
for(int i = 0; i < f; i++){
scanf("%d",&x);
sta[x] = true;
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
if(i == j) edge[i][j] = 0;
else edge[i][j] = inf;
}
}
int u,v,w;
while(scanf("%d%d%d",&u,&v,&w) == 3){
edge[u][v] = edge[v][u] = w;
}
return true;
}
void floyd(){
for(int k = 1; k <= n; k++){
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
edge[i][j] = min(edge[i][j],edge[i][k]+edge[k][j]);
}
}
}
}
void solve(){
floyd();
for(int i = 1; i <= n; i++) dist[i] = inf;
//用已存在的消防站来确定每个路口离消防站的距离
for(int i = 1; i <= n; i++){
if(!sta[i]) continue;
for(int j = 1; j <= n; j++){
dist[j] = min(dist[j],edge[i][j]);
}
}
int index = 1;
int minimum = inf;
int t_dist[maxn];
//放置消防站
for(int i = 1; i <= n; i++){
if(sta[i]) continue;
int maximum = -inf;
for(int j = 1; j <= n; j++) t_dist[j] = dist[j];
for(int j = 1; j <= n; j++){
t_dist[j] = min(t_dist[j],edge[i][j]);
maximum = max(t_dist[j],maximum);
}
if(maximum < minimum){
minimum = maximum;
index = i;
}
}
printf("%d\n",index);
}
int main(){
while(input()){
solve();
}
return 0;
}
spfa代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
using namespace std;
const int inf = 1000000000;
const int maxn = 505;
struct node{
int v,w;
node(int _v, int _w){
v = _v, w = _w;
}
};
int f,n;
bool sta[maxn];//消防站
vector<node> list[maxn];
int dist[maxn];
bool inq[maxn];
bool input(){
if(scanf("%d%d",&f,&n) != 2) return false;
int x;
for(int i = 1; i <= n; i++) sta[i] = false;
for(int i = 0; i < f; i++){
scanf("%d",&x);
sta[x] = true;
}
for(int i = 1; i <= n; i++) list[i].clear();
int u,v,w;
while(scanf("%d%d%d",&u,&v,&w) == 3){
list[u].push_back(node(v,w));
list[v].push_back(node(u,w));
}
return true;
}
void spfa(int s, int *d){
queue<int> q;
for(int i = 1; i <= n; i++){
inq[i] = false;
}
d[s] = 0;
q.push(s);
while(!q.empty()){
int u = q.front(); q.pop(); inq[u] = false;
for(int i = 0; i < list[u].size(); i++){
int v = list[u][i].v;
int w = list[u][i].w;
if(d[u] + w < d[v]){
d[v] = d[u] + w;
if(!inq[v]){
q.push(v);
inq[v] = true;
}
}
}
}
}
void solve(){
for(int i = 1; i <= n; i++) dist[i] = inf;
for(int i = 1; i <= n; i++){
if(sta[i]){
spfa(i,dist);
}
}
int index = 1;
int minimum = inf;
int t_dist[maxn];
//放置消防站
for(int i = 1; i <= n; i++){
if(sta[i]) continue;
int maximum = -inf;
for(int j = 1; j <= n; j++) t_dist[j] = dist[j];
spfa(i,t_dist);
for(int j = 1; j <= n; j++) maximum = max(maximum,t_dist[j]);
if(maximum < minimum){
minimum = maximum;
index = i;
}
}
printf("%d\n",index);
}
int main(){
while(input()){
solve();
}
return 0;
}