1
1

yukicoder No.3 ビットすごろく 解説

Last updated at Posted at 2024-07-19

問題文

前提知識

bit云々

解説

幅優先探索の容量でやる
幅優先探索を知らない場合はこれを参照。
dist[i]=i個目のマスに行くときの最短手数。その段階で行けないときは-1。
遷移方法
iの__builtin_popcountをeと置く。
①$dist[i+e]=dist[i]+1(i+e\leqq n)$
②$dist[i-e]=dist[i]+1(i-e>0)$
こんな感じでやれば行ける。
一番最初に更新された数字が最短距離なので2回以上の更新は不要
またqueueには高々$N$回しかpushされず、__builtin_popcountの計算量は$O(1)$。よって実行時間は$O(N)$

C++での解答例

#include <bits/stdc++.h>
using namespace std;

int main(){
  int n;cin>>n;
  //dist[i]=移動手数
  //現段階で行けないときは-1
  vector<int> dist(n+1,-1);
  dist[1]=1;
  queue<int> que;
  que.push(1);
  while(!que.empty()){
    int u=que.front();que.pop();
    //ここからは遷移
    //__builtin_popcount(u)=uの二進数の桁が1になっている数=__builtin_popcount
    //uから1手で行けるのはu+__builtin_popcountかu-__builtin_popcount
    if(u+__builtin_popcount(u)<=n&&dist[u+__builtin_popcount(u)]==-1){
      dist[u+__builtin_popcount(u)]=dist[u]+1;
      que.push(u+__builtin_popcount(u));
    }
    if(u-__builtin_popcount(u)>0&&dist[u-__builtin_popcount(u)]==-1){
      dist[u-__builtin_popcount(u)]=dist[u]+1;
      que.push(u-__builtin_popcount(u));
    }
  }
  cout<<dist[n]<<endl;
}
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1