[BFS][bitset]luogu P3645 [APIO2015]雅加达的摩天楼
题面
https://www.luogu.com.cn/problem/P3645
分析
BFS即可,因为是无权无向图
如果设不重复状态 (i,j) 表示第 i 个楼上的狗子跳跃能力为 j ,那么至多有 $max(n,m)\sqrt{n}$ 种状态
不难证明,若 $j\leq \sqrt{n}$ 则至多有 $n\sqrt{n}$ 种, $j> \sqrt{n}$ 则至多有 $m\sqrt{n}$ 种(狗子最多有m个)
然后对于每个第一次BFS到的大楼,将所有的狗子都加入队列,如果不是第一次到,判断该状态是否出现过,未出现再加入,即可保证复杂度严格为$ O((n+m)\sqrt{n})$
判重可以用 bitset 或者 hash(手写,别用unordered_map)
代码
#include <iostream> #include <cstdio> #include <queue> #include <vector> #include <bitset> using namespace std; typedef long long ll; const int N=3e4+10; struct Doge { int pos,p,step; }; int n,m; int b[N],p[N]; bitset<N> w[N]; queue<Doge> q; vector<int> v[N]; bool vis[N]; void BFS() { for (int i=0;i<v[b[0]].size();i++) if (!w[b[0]].test(v[b[0]][i])) q.push((Doge){b[0],v[b[0]][i],0}),w[b[0]].set(v[b[0]][i]);vis[b[0]]=1; while (!q.empty()) { Doge u=q.front();q.pop(); if (u.pos==b[1]) {printf("%d\n",u.step);return;} if (u.pos-u.p>=0) { if (!vis[u.pos-u.p]) for (int i=0;i<v[u.pos-u.p].size();i++) if (!w[u.pos-u.p].test(v[u.pos-u.p][i])) q.push((Doge){u.pos-u.p,v[u.pos-u.p][i],u.step+1}),w[u.pos-u.p].set(v[u.pos-u.p][i]); vis[u.pos-u.p]=1; if (!w[u.pos-u.p].test(u.p)) q.push((Doge){u.pos-u.p,u.p,u.step+1}),w[u.pos-u.p].set(u.p); } if (u.pos+u.p<n) { if (!vis[u.pos+u.p]) for (int i=0;i<v[u.pos+u.p].size();i++) if (!w[u.pos+u.p].test(v[u.pos+u.p][i])) q.push((Doge){u.pos+u.p,v[u.pos+u.p][i],u.step+1}),w[u.pos+u.p].set(v[u.pos+u.p][i])=1; vis[u.pos+u.p]=1; if (!w[u.pos+u.p].test(u.p)) q.push((Doge){u.pos+u.p,u.p,u.step+1}),w[u.pos+u.p].set(u.p); } } printf("-1\n"); } int main() { scanf("%d%d",&n,&m); for (int i=0;i<m;i++) scanf("%d%d",&b[i],&p[i]),v[b[i]].push_back(p[i]); BFS(); }
在日渐沉没的世界里,我发现了你。