NYOJ 210 Fire Station

针对已有消防站布局问题,通过最短路径算法优化新建站点位置,以缩短居民到达最近消防站的距离。采用SPFA算法避免重复计算,提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题链接

题意:有f个消防站已经建在十字路口,n个十字路口,每个路口附近都有居民居住,有些居民抗议他离最近的消防站太远了,所以现在需要再建

一个消防站,使得所有居民最近消防站最远的距离最近(有点拗口)。


题解:由于f<=100,n<=500,所以感觉可以直接算,首先要求出居民最近消防站的距离,这个就可以转换成已有的消防站到居民的距离中最小,很容易想到的是直接对所有消防站求一次最短路每个点取所有最短路中最小的,这样就可以知道所有居民最近的消防站的最远距离(求一次最大值),然后就可以枚举所有没有消防站的十字路口求最短路,和前面求出所有居民最近的消防距离再取最小值(这样就假设消防站建在此处),看最大值是否比没建此消防站的距离小,距离小就可以更新,取距离最小的那个十字路口。这里还需要注意的是输入路径时是以一个空行结束。这样是可以过poj和zoj的题目,但是在nyoj中还是超时了,其实可以发现在求最短路取最小值时是不需要每次去初始化,因为取的就是最小值,如果距离比当前值要大,就没必要更新,所以在求已有的消防站到居民的距离中最小的时候只需要更新一次,这样其实可以减少很多计算量,而且在这里用spfa比较好,用Dijkstra时不要用优先队列,因为使用优先队列时不一定是将最小的加入队列的,所以会导致超时,在后面新建消防站也用这种方法就可以了,反正都是求的最小值,不过注意这个时候不要将原来数据覆盖了。

#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <utility>
#include <map>
#include <set>
#include <queue>
#include <vector>
#include <iostream>
#include <stack>
using namespace std;
#define INF 0x3f3f3f3f
#define eps 1e-6
#define CLR( a, v ) memset ( a, v, sizeof ( a ) )
#define LL long long
#define DBUG printf ( "here!!!" )
#define rep( i, a, b ) for ( int i = ( a ); i < ( b ); i ++ )
#define PB push_back
#define ULL unsigned long long
#define PI acos ( -1.0 )
#define lson l, m, rt << 1
#define rson m+1, r, rt << 1 | 1
#define lowbit( x ) ( ( x )&( -x ) )
#define CASE int T; scanf ( "%d", &T ); for ( int cas = 1; cas <= T; cas ++ )
#define ALL( x ) x.begin ( ), x.end ( )
#define INS( x ) x, x.begin ( )
typedef pair < int, int > Pii;
typedef pair < double, double > Pdd;
typedef set < int > Set;
const int maxn = 505, N = maxn*20;
int read_int ( )
{
    int res = 0;
    int ch;
    while ( ( ch = getchar ( ) ) && ! ( ch >= '0' && ch <= '9' ) )
    {
        if ( ch == -1 )
            return -1;
    }
    while ( ch >= '0' && ch <= '9' )
    {
        res = res*10+( ch-'0' );
        ch = getchar ( );
    }
    return res;
}
struct node
{
    int to, len;
    node ( ) { }
    node ( int v, int l ) : to ( v ), len ( l ) { }
};
int d[maxn], mn[maxn], tmp[maxn];
int head[N], nxt[N], pos, n;
node mp[N];
bool has[maxn], inq[maxn];
void addEdge ( int u, node t )
{
    mp[pos] = t;
    nxt[pos] = head[u];
    head[u] = pos ++;
}
void spfa ( int s )
{
    queue < int > q;
    d[s] = 0;
    q.push ( s );
    CLR ( inq, false );
    while ( ! q.empty ( ) )
    {
        int u = q.front ( );
        q.pop ( );
        inq[u] = false;
        for ( int i = head[u]; ~ i; i = nxt[i] )
        {
            int val = mp[i].len, v = mp[i].to;
            if ( d[v] > d[u]+val )
            {
                d[v] = d[u]+val;
                if ( inq[v] == false )
                {
                    inq[v] = true;
                    q.push ( v );
                }
            }
        }
    }
}
char str[maxn];
void solve ( )
{
    int f, u, v, w, sta;
    while ( ~ scanf ( "%d%d", &f, &n ) )
    {
        CLR ( has, false );
        pos = 0;
        CLR ( head, -1 );
        for ( int i = 0; i < f; i ++ )
        {
            scanf ( "%d", &sta );
            has[ sta ] = true;
        }
        getchar ( );
        while ( gets ( str ) != '\0' && str[0] != '\0' )
        {
            u = v = w = -1;
            int len = strlen ( str );
            for ( int i = 0; i < len; )
            {
                if ( str[i] >= '0' && str[i] <= '9' )
                {
                    int val = 0;
                    while ( i < len && str[i] >= '0' && str[i] <= '9' )
                    {
                        val = val*10+( str[i]-'0' );
                        i ++;
                    }
                    if ( u == -1 )
                        u = val;
                    else if ( v == -1 )
                        v = val;
                    else
                        w = val;
                }
                else
                    i ++;
            }
            addEdge ( u, node ( v, w ) );
            addEdge ( v, node ( u, w ) );
        }
        CLR ( d, 0x3f );    //只初始化一次减少计算量
        for ( int i = 1; i <= n; i ++ )
        {
            if ( has[i] == false )
                continue ;
            spfa ( i );
        }
        int ans = 0, pos = 1;
        for ( int i = 1; i <= n; i ++ )
        {
            mn[i] = d[i];   //保存中间值
            ans = max ( ans, mn[i] );
        }
        for ( int i = 1; i <= n; i ++ )
        {
            if ( has[i] )
                continue ;
            for ( int j = 1; j <= n; j ++ )
                d[j] = mn[j];
            spfa ( i );
            int mx = 0;
            for ( int j = 1; j <= n; j ++ )
                mx = max ( d[j], mx );
            if ( ans > mx )
            {
                ans = mx;
                pos = i;
            }
        }
        printf ( "%d\n", pos );
    }
}
int main ( )
{
    solve ( );
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值