1. 程式人生 > 其它 >P3645-[APIO2015]雅加達的摩天樓【bfs,根號分治】

P3645-[APIO2015]雅加達的摩天樓【bfs,根號分治】

技術標籤:廣搜luoguAPIObfs根號分治

正題

題目連結:https://www.luogu.com.cn/problem/P3645


題目大意

n n n個點, m m m條狗,第 i i i條狗可以往左或者右跳恰好 p i p_i pi步,開始是 0 0 0號狗,每次跳躍到達一個點可以選擇換一條狗,求到 1 1 1號狗所在點的最短路。


解題思路

為了方便設 n , m n,m n,m同級
對於 p i ≤ n p_i\leq \sqrt n pin 的狗, p i p_i pi的種類只有 n \sqrt n n 級別,每條狗能到達的點是 O ( n ) O(n)

O(n)級別
對於 p i > n p_i>\sqrt n pi>n 的狗, p i p_i pi的種類有 O ( n ) O(n) O(n)級別,每條狗能到達的點數是 O ( n ) O(\sqrt n) O(n )級別。

所以總共的狀態數不超過 O ( n n ) O(n\sqrt n) O(nn )個,暴力 b f s bfs bfs就好了。

對於儲存狀態可以按照 n \sqrt n n 為分界用兩種不同的方式儲存,當然還有更暴力的方法就是直接用 b i t s e t bitset bitset存。

時間複雜度 O ( n n ) O(n\sqrt n)

O(nn )


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<bitset>
#include<vector>
#define mp(x,y) make_pair(x,y)
using namespace std;
const int N=3e4+10;
int n,m,S,T;
bitset<N>v[N];
vector<int>s[N];
queue<pair<
pair<int,int> ,int> >q; int bfs(){ for(int i=0;i<s[S].size();i++) q.push(mp(mp(S,s[S][i]),0)),v[S][s[S][i]]=1; while(!q.empty()){ int x=q.front().first.first,w=q.front().first.second,d=q.front().second; int y=x-w; if(y>=0){ if(y==T)return d+1; for(int i=0;i<s[y].size();i++) if(!v[y][s[y][i]]) q.push(mp(mp(y,s[y][i]),d+1)),v[y][s[y][i]]=1; if(!v[y][w])q.push(mp(mp(y,w),d+1)),v[y][w]=1; } y=x+w; if(y<n){ if(y==T)return d+1; for(int i=0;i<s[y].size();i++) if(!v[y][s[y][i]]) q.push(mp(mp(y,s[y][i]),d+1)),v[y][s[y][i]]=1; if(!v[y][w])q.push(mp(mp(y,w),d+1)),v[y][w]=1; } q.pop(); } return -1; } int main() { scanf("%d%d",&n,&m); for(int i=0;i<m;i++){ int x,w; scanf("%d%d",&x,&w); if(i==0)S=x; if(i==1)T=x; s[x].push_back(w); } if(S==T)return puts("0")&0; printf("%d\n",bfs()); return 0; }