C++で解く!ブロックタワーの高さの差(醜さ)を最小化するプログラム
n個の要素を持つ配列Aがあるとします。一列にn個のブロックタワーが並んでおり、i番目のタワーの高さはA[i]です。1日ごとに、次の操作を1回だけ実行できます。
「2つの異なるインデックスiとj(i ≠ j)を選び、タワーiからタワーjへブロックを1つ移動する」——この操作により、A[i]は1減少し、A[j]は1増加します。
建物の「醜さ」とは、max(A) − min(A)、すなわち最も高いタワーと最も低いタワーの高さの差として定義されます。この記事では、達成可能な最小の醜さを求める方法を解説します。
問題の例
例として、入力がA = [1, 2, 3, 1, 5]の場合を考えてみましょう。このときの出力は1になります。
- i = 2、j = 0として操作を3回行うと、配列は[2, 2, 2, 1, 5]になります。
- 次にi = 4、j = 3とすると、配列は[2, 2, 2, 2, 4]になります。
- さらにi = 4、j = 2とすると、配列は[2, 2, 3, 2, 3]となり、この時点での醜さは3 − 2 = 1です。
解法のポイント
この問題の鍵となるのは、「すべてのタワーの高さの合計値」に注目することです。
- 合計がnで割り切れる場合:全タワーを同じ高さ(合計 ÷ n)に揃えることができるため、醜さの最小値は0になります。
- 合計がnで割り切れない場合:タワーの高さは整数であるため、どうしても最低1の差が残ってしまいます。一方、ブロックは自由に移動できるため、差を1まで縮めることは必ず可能です。したがって、醜さの最小値は1になります。
手順
以上を踏まえ、以下の手順に従って問題を解きます。
sum := 0
x := 0
n := size of A
for initialize i := 0, when i < n, update (increase i by 1), do:
sum := sum + A[i]
if sum mod n is same as 0, then:
return 0
return 1
C++での実装例
理解を深めるために、実際のC++コードを見てみましょう。
#include <bits/stdc++.h>
using namespace std;
int solve(vector<int> A) {
int sum = 0, x = 0;
int n = A.size();
for (int i = 0; i < n; i++)
sum += A[i];
if (sum % n == 0)
return 0;
return 1;
}
int main() {
vector<int> A = { 1, 2, 3, 1, 5 };
cout << solve(A) << endl;
}
入力
{ 1, 2, 3, 1, 5 }
出力
1
このように、合計値を要素数nで割った余りが0かどうかを確認するだけで、O(n)の計算量で答えを求められる非常にシンプルなアルゴリズムとなっています。
-
C++で2次元デカルト座標点をすべて接続する最小コストを求めるプログラム
問題の概要2次元デカルト座標上の点のリスト(x, y)が与えられたとします。点(x0, y0)と(x1, y1)を接続するときのコストは、|x0 − x1| + |y0 − y1|(マンハッタン距離)で表されます。任意の数の点を接続できる場合、すべての点がひとつのパスでつながるようにするために必要な最小コストを求めます。例えば、入力が points = [[0, 0], [0, 2], [0, -2], [2, 0], [-2, 0], [2, 3], [2, -3]] の場合を考えてみましょう。このとき出力は 14 になります。その理由は以下の通りです。(0, 0) から (0, 2)、(0
-
C++でノード値の合計が最小となる二分木のレベルを求めるプログラム
二分木(バイナリツリー)を考えます。根(ルート)のレベルを1とし、その子のレベルを2、さらにその下のレベルを3というように定義します。このとき、レベルXに存在するすべてのノードの値の合計が最小になるような、最も小さいレベルXを見つけるのが本記事の目的です。例として、次のような二分木を考えてみましょう。この場合、出力は 2 となります。なぜなら、レベル2のノードの値の合計は 4 + (-10) = -6 となり、これが全レベルの中で最小だからです。解法のアプローチこの問題は、幅優先探索(BFS)を使って各レベルごとにノードの値の合計を計算し、その中で最小となるレベルを記録していくことで解けます。