APIO2015 Bali Sculptures UOJ111 BZOJ4070

好像大家的做法都是最短路。
由於邊權都是1嘛,所以我就二五二五的動手bfs了……
但是純搜好像是不行的,大家還好心提醒我uoj卡的很嚴,會TLE,所以我就用了一些bool數組記錄,要是算過了就不再算了(這好像是廢話2333)
由於剛學了莫隊算法(不知道莫隊的戳這裏),所以對分塊思想的印象比較深,於是就開始分塊水這個題目23333
大概做法是取一個限制ss,如果狗跳的距離小於ss,就用數組記下來;否則就直接不管那麼多跳就行了(一共30000/ss次)
(因爲數組開太大會MLE的2333所以就分塊啊)

具體細節的處理放在註釋

#include <iostream>
#include <cstdlib>
#include <vector>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std ;
bool Read ( int &x ) {
    x = 0 ; char c = getchar() ; bool f = 0 ;
    while ( !isdigit(c) ) {
        if ( c == '-' ) f = 1 ;
        if ( c == EOF ) return false ;
        c = getchar() ;
    }
    while ( isdigit(c) ) {
        x = 10*x + c - '0' ;
        c = getchar() ;
    } if (f) x = -x ;
    return true ;
} //讀入優化不解釋
const int ss = 110 ; // 隨便一個限制
const int maxn = 30005 ;
struct node {
    int dir, lenth, tim, now ;
    //當前狗的方向、步長;現在跳了幾步、在那個房子上
} s[maxn] ;
queue <node> q ;
int n, m, A[maxn], B[maxn] ;
bool mark[maxn][ss+1], mk[maxn] ;
//mark[i][j]代表:在點i開始一隻步長爲j的狗
//mk[i]代表:點i
//都指示是否被計算過
vector <int> G[maxn] ;
//G[i]存儲所有的步長,由於可能有一些狗步長一樣,所以就不記錄狗
void update ( int x, int tim ) { //換條狗
    if ( mk[x] ) return ;
    mk[x] = 1 ;
    int i, j, siz = G[x].size(), u, len ;
    for ( i = 0 ; i < siz ; i ++ ) {
        len = G[x][i] ;
        if ( x+len==A[2] || x-len==A[2] ) {
            printf ( "%d\n", tim+1 ) ;
            exit(0) ;
            //跳到終點了,直接再見
        }
        if ( len <= ss ) {
            if ( mark[x][len] ) continue ;
            mark[x][len] = 1 ;
            //限制內,需要更新標記
        }
        if ( x+len <= m ) q.push( (node){1, len, tim+1, x+len} ) ;
        if ( x-len >= 1 ) q.push( (node){0, len, tim+1, x-len} ) ;
    }
}
int bfs() {
    int i, u, x, tim, len, siz ;
    if ( A[1] == A[2] ) return 0 ;
    while ( !q.empty() ) q.pop() ;
    update ( A[1], 0 ) ;
    while ( !q.empty() ) {
        node tmp = q.front() ;
        q.pop() ;
        x = tmp.now, len = tmp.lenth, tim = tmp.tim ;
        if ( x+len == A[2] || x-len == A[2] ) return tim+1 ;
        update ( x, tim ) ;
        //將所有相關的狗的情況都放進bfs隊列
        if ( len <= ss ) {
            //限制範圍內
            if ( tmp.dir ) {
            //向編號大的方向跳
                if ( x+len <= m && !mark[x][len] )
                    q.push( (node){1, len, tim+1, x+len} ) ;
                mark[x][len] = 1 ;
            } else {
                if ( x-len >= 1 && !mark[x][len] ) 
                    q.push( (node){0, len, tim+1, x-len} ) ;
                mark[x][len] = 1 ;
            }
        } else {
            if ( tmp.dir == 0 && x-len >= 1 ) 
                q.push( (node){0, len, tim+1, x-len} ) ;
            else if ( x+len <= m ) 
                q.push( (node){1, len, tim+1, x+len} ) ;
        }
    }
    return -1 ;
}
int main() {
    int i, j, k ;
    Read(m) ; Read(n) ;
    for ( i = 1 ; i <= n ; i ++ ) {
        Read(A[i]) ; Read(B[i]) ;
        ++ A[i] ;
        //個人習慣將點從1~n編號
    }
    for ( i = 1 ; i <= n ; i ++ ) 
        G[A[i]].push_back(B[i]) ;
    printf ( "%d\n", bfs() ) ;
    return 0 ;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章