ZOJ Problem Set - 1857

Fire Station

Time Limit: 2 Seconds       Memory Limit: 65536 KB

A city is served by a number of fire stations. Some residents have complained that the distance from their houses to the nearest station is too far, so a new station is to be built. You are to choose the location of the fire station so as to reduce the distance to the nearest station from the houses of the disgruntled residents. 

The city has up to 500 intersections, connected by road segments of various lengths. No more than 20 road segments intersect at a given intersection. The location of houses and firestations alike are considered to be at intersections (the travel distance from the intersection to the actual building can be discounted). Furthermore, we assume that there is at least one house associated with every intersection. There may be more than one firestation per intersection.


Input

The first line of input contains two positive integers: f,the number of existing fire stations (f <= 100) and i, the number of intersections (i <= 500). The intersections are numbered from 1 to i consecutively. f lines follow; each contains the intersection number at which an existing fire station is found. A number of lines follow, each containing three positive integers: the number of an intersection, the number of a different intersection, and the length of the road segment connecting the intersections. All road segments are two-way (at least as far as fire engines are concerned), and there will exist a route between any pair of intersections.

Subsequent test cases are separated with a single blank line.


Output

You are to output a single integer for each test case: the lowest intersection number at which a new fire station should be built so as to minimize the maximum distance from any intersection to the nearest fire station.


Sample Input

1 6
2
1 2 10
2 3 10
3 4 10
4 5 10
5 6 10
6 1 10


Sample Output

5

题意:有很多路口,一些路口上有消防站,求每个路口到最近消防站的距离的最大值。这是没有限制条件下的,但题目有个限制条件,可以增加一个消防站,求增加在那个消防站,距离的最大值最小。如果有多组解,输出消防站下标最小的。

其实这题用floyd极其简单,得到两两之间的最短距离,然后枚举每个消防站,对每个点更新最短路的最小值(因为只要存在一个消防站即可)。处理完后,统计所有点距离的最大值。最后枚举在哪个位置加消防站,同样看看此时最大值是否会被修改为更小的。

但看了一下站点的个数,最大为500,那么O(n^3)显然超时,于是退而求其次,用spfa这种算法,这种算法在此题的复杂度最好接近O(n^2),也就是平均情况下spfa是O(kn)的,但实际最坏情况可能会退化到bellman-ford

,那么总复杂度又到了O(n^3)。但没有办法,最短路也只有spfa算最快的了。实际这道题,测试数据极其水吧。spfa妥妥的,据说floyd可以过poj的这题。

ps:此题读入格式极其恶心。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#define Maxn 510
using namespace std;

struct line{
    int to,w;
    line(int t=0,int ww=0):to(t),w(ww){}
}p[20010];
int fire[Maxn],dist[Maxn],vis[Maxn];
int q[Maxn],ans[Maxn],head[Maxn],nxt[20010];
char s[Maxn];
const int inf=0x3f3f3f3f;
void spfa(int u,int m){
    for(int i=1;i<=m;i++)
        dist[i]=inf,vis[i]=0;
    dist[u]=0;
    int s=0,e;
    q[e=1]=u;
    while(s!=e){
        int v=q[s=(s+1)%Maxn];
        vis[v]=0;
        for(int i=head[v];i!=-1;i=nxt[i]){
            int r=p[i].to,w=p[i].w;
            if(dist[v]+w<dist[r]){
                dist[r]=dist[v]+w;
                if(!vis[r]){
                    q[e=(e+1)%Maxn]=r;
                    vis[r]=1;
                }
            }
        }
    }
}
int main()
{
    int n,m,fr,to,w,x;
    char *re;
    while(gets(s)){
        sscanf(s,"%d%d",&n,&m);
        memset(fire,0,sizeof fire);
        memset(head,-1,sizeof head);
        memset(ans,0x3f,sizeof ans);
        for(int i=0;i<n;i++){
            scanf("%d",&x);
            fire[x]=1;
        }
        gets(s);
        int tot=0;
        while(re=gets(s)){
            if(!s[0]) break;
            sscanf(s,"%d%d%d",&fr,&to,&w);
            p[tot]=line(to,w),nxt[tot]=head[fr],head[fr]=tot++;
            p[tot]=line(fr,w),nxt[tot]=head[to],head[to]=tot++;
        }
        for(int i=1;i<=m;i++)
            if(fire[i]){
                spfa(i,m);
                for(int j=1;j<=m;j++)
                    ans[j]=min(ans[j],dist[j]);
            }
        int res=0,maxx,id=1;
        for(int i=1;i<=m;i++) res=max(res,ans[i]);
        for(int i=1;i<=m;i++)
            if(!fire[i]){
                spfa(i,m);
                maxx=0;
                for(int j=1;j<=m;j++)
                    maxx=max(maxx,min(ans[j],dist[j]));
                if(maxx<res) res=maxx,id=i;
            }
        printf("%d\n",id);
        if(!re) break;
    }
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值