マユログ

プログラミングが大好きな女子大生の日記。

すずめでも分かる「bit全探索」

この記事をシェアする

記憶喪失になってbit全探索を1から理解しないといけなくなったときのために、(自分用に)解説しておこうと思います。

bit全探索とは

部分集合を列挙するときに使えるアルゴリズムです。

f:id:Mayu_snba19:20200512155832p:plain

つまり、こういうことができます。

実装はこんな感じ

for (int bit = 0; bit < (1 << n); ++bit) {
  for (int i = 0; i < n; ++i) {
    if (bit & (1 << i)) {
      //何か処理を書く
    }
  }
}

これを見せられても、何をしているのか訳がわかりませんね。細かく見てみましょう。

for (int bit = 0; bit < (1 << n); ++bit) って何してるの?

ここで特にわからないのは、<<の部分だと思います。<<はシフト演算子と呼ばれています。シフト演算子は、数値の各ビットを左または右へシフトさせるための演算子です。<<だと左に、>>だと右にいきます。

各ビットをシフトするということは、下図のように遷移していくことを表します。

f:id:Mayu_snba19:20200512163232p:plain

2進数の状態で遷移します!(10進数で35が350になったりしません!!!)

すずめ「1が1回左にシフトされるとどうなりますか?」

うさぎ「00001が00010になるので、10進数だと2になります。」

すずめ「では、2が1回左にシフトされるとどうなりますか?」

うさぎ「00010が00100になるので、4になります!」

ここまでで、シフトされる度に2倍になっていっているということが分かると思います。

ということは、for (int bit = 0; bit < (1 << n); ++bit) {1<<nは、「1をn回左にシフトする」=「2のn乗」ですね!

if (bit & (1 << i)) の部分

ここでは何をしているのでしょうか。

&は、各ビットについて「両方のビットが1ならば1」という操作を適用する演算子です。for文によってn回シフトされるので、下図のように全ての桁のbitがたっているかどうかを調べることができます!

f:id:Mayu_snba19:20200512170738p:plain

このビットを、その数値を取るか取らないかの2つの状態に当てはめることによって、全探索が行えます!具体的に言うと、C - Skill Upの問題で2冊の参考書が売っていたとするとき、「両方買わない」「1冊目を買う」「2冊目を買う」「1冊目と2冊目を買う」を、「00」「01」「10」「11」に当てはめて調べることができます。(ほら、全部で2のn乗の状態がありますね!)

実装しよう

C - Skill Upを解きます。

bit全探索を理解できると、やるだけですね!!

おしまい。