好像大家的做法都是最短路。
由於邊權都是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 ;
}