C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++で解く「貧しい豚(Poor Pigs)」問題 ― 毒入りのバケツを見つける最小の豚の数

ここに1000個のバケツがあるとしましょう。そのうち1つだけに毒が入っており、残りはすべて水が入っています。見た目はどれもまったく同じで、区別がつきません。毒を飲んだ豚は15分以内に死んでしまうため、1時間以内に毒の入ったバケツを特定するには、最低何頭の豚が必要でしょうか?

問題の一般化

まず、この問題を一般化してみましょう。条件は次のとおりです。

  • n個のバケツがあり、そのうちちょうど1つに毒が入っている
  • 毒を飲んだ豚は m 分以内に死ぬ
  • p 分以内に毒のバケツを特定したい

このとき必要な豚の最小頭数を求めるのが目標です。例えば n = 1000、m = 15、p = 60 の場合、答えは 5 になります。

解法のポイント:「1頭の豚で複数回テストできる」

この問題を解く鍵は、1頭の豚が1回しか使えないわけではないという点にあります。テスト可能な時間が死亡までの時間の何倍かに応じて、豚は「何ラウンド目で死んだか」「最後まで生き残ったか」といった複数の状態を取り得ます。

具体的には、1頭の豚が取り得る状態の数は次の式で表せます。

状態数 = minutesToTest / minutesToDie + 1

例えば 60分 ÷ 15分 + 1 = 5 状態です。この状態数を「底」、豚の頭数を「指数」とする累乗が、識別可能なバケツの組み合わせの総数になります。したがって、次を満たす最小の ret(豚の頭数)を求めればよいのです。

(minutesToTest / minutesToDie + 1)^ret ≥ バケツの数

アルゴリズムの手順

  • ret := 0 で初期化する
  • (minutesToTest / minutesToDie + 1)^ret < バケツの数 である間、ret を1ずつ増やし続ける
  • ret を返す

C++での実装例

#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
   int poorPigs(int buckets, int minutesToDie, int minutesToTest) {
      int ret = 0;
      while(pow((minutesToTest / minutesToDie + 1), ret) < buckets) ret++;
      return ret;
   }
};
main(){
   Solution ob;
   cout << (ob.poorPigs(1000,15,60));
}

入力

1000
15
60

出力

5

なぜ答えは5なのか?

この例では、1頭あたりの状態数は 60 ÷ 15 + 1 = 5 です。豚の頭数ごとに識別できるバケツ数を計算すると、

  • 4頭の場合:5^4 = 625 → 1000個は識別できない
  • 5頭の場合:5^5 = 3125 → 1000個を十分にカバーできる

このため、必要な最小の豚の数は 5頭 となります。各バケツに一意の番号を5進法で割り当て、それぞれの桁に対応する豚がいつ死んだか(あるいは生き延びたか)を観察すれば、どのバケツに毒が入っていたかを正確に特定できます。

  1. C++で解く「ジャンプゲームV」:メモ化再帰による最大訪問インデックス数の求め方

    問題の概要整数型の配列 arr と整数 d が与えられます。1ステップごとに、インデックス i から次の場所へジャンプできます。右方向: i + x(ただし i + x < n、かつ x は 1 以上 d 以下)左方向: i - x(ただし i - x >= 0、かつ x は 1 以上 d 以下)ここで n は配列のサイズです。さらに重要な制約として、インデックス i から j へジャンプできるのは、arr[i] > arr[j] であり、かつ i と j の間にあるすべてのインデックス k に対して arr[i] > arr[k] を満たす場合のみです。つまり、より低

  2. C++で約数がちょうど4個の整数の約数の総和を求める方法

    整数配列 nums が与えられたとき、その中から「約数がちょうど4個」である整数を見つけ出し、それらの約数の総和を計算する問題を考えてみましょう。もし該当する整数が配列内に1つも存在しない場合は、0 を返します。例えば、入力が [21, 4, 7] の場合、出力は 32 になります。これは次のような理由によるものです。21 の約数は 1, 3, 7, 21 の4つ → 条件を満たす4 の約数は 1, 2, 4 の3つ → 条件を満たさない7 の約数は 1, 7 の2つ → 条件を満たさないしたがって、答えは条件を満たす 21 の約数の総和である 32 となります。解法のアプローチこの問題を解く