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

C++でブロック構築にかかる最小時間を求めるアルゴリズム

ブロックのリストがあるとします。blocks[i] = t の場合、i 番目のブロックを構築するには t 単位の時間が必要です。1つのブロックは、必ずちょうど1人の作業員だけが担当できます。各作業員は「2人の作業員に分割する」か「ブロックを1つ構築して退場する」のいずれかの行動を選択でき、それぞれの決断には一定の時間がかかります。作業員を2人に分割するときのコストは、split という数値として与えられます。

問題例

たとえば、blocks = [1, 2]、split = 5 という入力の場合、出力は 7 になります。これは、まず 5 単位の時間をかけて作業員を2人に分割し、それぞれにブロックを1つずつ割り当てることで、合計コストが 5 + max(1, 2) = 7 となるためです。

解法のアプローチ

この問題は、ハフマン符号化とよく似た貪欲法(グリーディー)で効率よく解けます。ポイントは、常に最も小さい2つの値を組み合わせていくことです。具体的な手順は以下の通りです。

  • 最小ヒープ(昇順の優先度付きキュー)pq を用意します

  • i := 0 から始めて、i が blocks のサイズ未満である間、i を1ずつ増やしながら次を実行します

    • blocks[i] を pq に挿入します

  • pq のサイズが1より大きい間、次を繰り返します

    • pq から最小の要素を取り出します

    • x := pq の先頭(次に小さい)要素とし、pq から削除します

    • split + x を pq に挿入します

  • pq の先頭要素を答えとして返します

このアルゴリズムが正しく動作する理由は、作業員の分割が二分木の構造をなすためです。構築時間の短いブロックほど深い位置(多くの分割を経由した位置)に置いても全体への影響が小さいため、常に小さい方から統合していくのが最適となります。

それでは、理解を深めるために以下の実装例を見てみましょう。

C++実装例

#include <bits/stdc++.h>
using namespace std;
class Solution {
   public:
   int minBuildTime(vector<int>& blocks, int split) {
      priority_queue<int, vector<int>, greater<int> > pq;
      for (int i = 0; i < blocks.size(); i++)
      pq.push(blocks[i]);
      while (pq.size() > 1) {
         pq.pop();
         int x = pq.top();
         pq.pop();
         pq.push(split + x);
      }
      return pq.top();
   }
};
main(){
   Solution ob;
   vector<int> v = {1,2};
   cout << (ob.minBuildTime(v, 5));
}

入力

{1,2}, 5

出力

7
  1. C++で二分木の最小深度を求める方法を解説

    二分木が与えられたとき、その木の最小深度(minimum depth)を求めることを考えます。最小深度とは、根ノードから最も近い葉ノードまでの最短経路に含まれるノード数のことです。 例えば、次のような二分木が入力として与えられた場合を考えてみましょう。 この場合、出力は 2 になります。これは、根ノード 3 から葉ノード 9 までの経路が最短だからです。 解決のためのアプローチ この問題は、幅優先探索(BFS)を用いて各レベルを順番に調べることで効率的に解決できます。手順は以下の通りです。 ツリーノードを格納する配列 aa を定義し、その末尾に root を挿入します 別の配列 ak を

  2. C++で解くナイトの最短移動回数問題:メモ化再帰による効率的な解法

    問題概要無限に広がるチェス盤を考えます。座標は -∞ ~ +∞ の範囲に及び、ナイトは初期状態でマス [0, 0] に配置されています。ナイトの移動は下図のように8通りあり、それぞれ「縦または横の方向に2マス、その後それと直交する方向に1マス」という動きになります。この問題では、ナイトを目標のマス [x, y] まで移動させるのに必要な最小手数を求めます。なお、必ず目的地に到達できる(解が存在する)ことが保証されています。具体例たとえば入力が x = 5、y = 5 の場合、出力は 4 になります。これは次のような経路で到達できるためです。[0,0] → [2,1] → [4,2] → [3,