• 「HDU5361」In Touch


    题目

    点这里看题目。

    分析

    首先注意到问题就是一个最短路的模型,但是边是连在区间上的,这提示我们应该使用数据结构优化建图

    考虑一个不那么粗暴的做法。一种想法是,由于用 Dijkstra 跑最短路的时候,只要出了堆就可以不用管了,那么我们可以每次只访问区间内有效的位置;这个位置可以使用链表/并查集维护。

    然而这个方法并没有用......Dijkstra 和 BFS 不同的地方在于,Dijkstra 中每个点虽然只会被出一次堆,但是会被访问多次,而 BFS 则只会被访问一次。此题还有一个性质,边权只和边的起点相关,如果我们在堆里维护好到达某个点的最短距离,等到这个最短距离被取出了之后,我们再去找可以到达的点,并且将这个最短距离赋给那些点,就可以保证每个点只访问一次。

    小结:

    1. 理清每个算法之间的差异,避免一些理解错误的问题;
    2. 注意,求最短路的时候,“计算距离”和“将距离对应到点”并非绑定在一起的,通过将这两个过程拆开我们可以处理这种特殊情况;

    代码

    #include <queue>
    #include <cstdio>
    #include <utility>
    #include <iostream>
    
    #define rep( i, a, b ) for( int i = (a) ; i <= (b) ; i ++ )
    #define per( i, a, b ) for( int i = (a) ; i >= (b) ; i -- )
    
    typedef long long LL;
    
    const LL INF = 1e18;
    const int MAXN = 2e5 + 5;
    
    template<typename _T>
    void read( _T &x )
    {
        x = 0; char s = getchar(); int f = 1;
        while( ! ( '0' <= s && s <= '9' ) ) { f = 1; if( s == '-' ) f = -1; s = getchar(); }
        while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar(); }
        x *= f;
    }
    
    template<typename _T>
    void write( _T x )
    {
        if( x < 0 ) putchar( '-' ), x = -x;
        if( 9 < x ) write( x / 10 );
        putchar( x % 10 + '0' );
    }
    
    typedef std :: pair<LL, int> Node;
    
    std :: priority_queue<Node, std :: vector<Node>, std :: greater<Node> > q;
    
    LL dist[MAXN];
    bool vis[MAXN];
    
    int fa[MAXN];
    int l[MAXN], r[MAXN], c[MAXN];
    int N;
    
    void MakeSet( const int n ) { rep( i, 1, n ) fa[i] = i; }
    int FindSet( const int u ) { return fa[u] = ( fa[u] == u ? u : FindSet( fa[u] ) ); }
    void UnionSet( const int u, const int v ) { fa[FindSet( u )] = FindSet( v ); }
    
    void Dijkstra( const int s )
    {
        MakeSet( N + 1 );
        while( ! q.empty() ) q.pop();
        rep( i, 1, N ) dist[i] = INF, vis[i] = false;
        q.push( std :: make_pair( dist[s] = c[s], s ) );
        while( ! q.empty() )
        {
            int u = q.top().second; q.pop(), vis[u] = true;
            int lef = std :: max( u - r[u], 1 ), rig = u - l[u];
            if( lef <= rig )
                for( int v = FindSet( lef ) ; v <= rig ; v = FindSet( v + 1 ) )
                {
                    if( dist[v] > dist[u] + c[v] ) 
                        q.push( std :: make_pair( dist[v] = dist[u] + c[v], v ) );
                    UnionSet( v, v + 1 );
                }
            lef = u + l[u], rig = std :: min( N, u + r[u] );
            if( lef <= rig )
                for( int v = FindSet( lef ) ; v <= rig ; v = FindSet( v + 1 ) )
                {
                    if( dist[v] > dist[u] + c[v] ) 
                        q.push( std :: make_pair( dist[v] = dist[u] + c[v] , v ) );
                    UnionSet( v, v + 1 );
                }
        }
    }
    
    int main()
    {
        int T;
        read( T );
        while( T -- )
        {
            read( N );
            rep( i, 1, N ) read( l[i] );
            rep( i, 1, N ) read( r[i] );
            rep( i, 1, N ) read( c[i] );
            Dijkstra( 1 );
            rep( i, 1, N ) 
            {
                if( vis[i] ) write( dist[i] - c[i] );
                else write( -1 ); putchar( i == N ? '
    ' : ' ' );
            }
        }
        return 0;
    }
    
  • 相关阅读:
    推荐一个博客,或许给技术流的自己一些启示
    Boost多线程-替换MFC线程
    Python:Matplotlib 画曲线和柱状图(Code)
    AI:机器人与关键技术--总是被科普
    OnLineML一:关于Jubatus 的简介...
    使用PCL::GPU::遇到问题
    dll文件:关于MFC程序不能定位输入点
    实践:使用FLANN.LSH进行检索
    模式识别两种方法:知识和数据
    几个方便编程的C++特性
  • 原文地址:https://www.cnblogs.com/crashed/p/15158381.html
Copyright © 2020-2023  润新知