[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();
}
View Code

 

posted @ 2021-03-25 19:37  Vagari  阅读(55)  评论(0编辑  收藏  举报