C++で1〜Nのすべての整数を部分和として表すために必要な最小の個数を求める方法
問題文
整数 N が与えられます。K 個の整数を選び、そのうちのいくつか(またはすべて)を足し合わせることで、1 から N までの範囲に含まれるすべての整数を作り出せるようにします。このとき必要な K の最小値を求めるのがこの問題の目的です。
例
N = 8 の場合、答えは K = 4 となります。
たとえば 1, 2, 3, 4 の 4 つの整数を選ぶと、それらをいくつか組み合わせるだけで、1 から 8 までのすべての数を作り出せます。
1 = 1
2 = 2
3 = 3
4 = 4
5 = 1 + 4
6 = 2 + 4
7 = 3 + 4
8 = 1 + 3 + 4
アルゴリズム
この問題は、与えられた整数 N のビット数(2進表現の桁数)を数えるだけで解くことができます。
K 個の整数から作れる空でない部分集合の和は、最大で 2^K − 1 通りです。1 から N までの N 個の数をすべてカバーするには 2^K − 1 ≥ N が必要であり、これを満たす最小の K は「N の 2進表現におけるビット数」と一致します。
計算量
N を 1 ビットずつ右シフトしながらカウントするため、時間計算量は O(log N)、空間計算量は O(1) と非常に効率的です。
C++での実装例
#include <bits/stdc++.h>
using namespace std;
int getMinNumbers(int n) {
int cnt = 0;
while (n) {
++cnt;
n = n >> 1;
}
return cnt;
}
int main() {
int n = 8;
cout << "Minimum required numbers = " << getMinNumbers(n) << endl;
return 0;
}
このプログラムをコンパイルして実行すると、次の出力が得られます。
出力
Minimum required numbers = 4
N = 8 は 2進数で「1000」と表され、ビット数は 4 です。そのため、必要な最小の整数の個数も 4 となります。
-
C++で数値Nを回文の和として表すために必要な最小の回文の個数を求める方法
問題の概要数値Nが与えられたとき、Nをいくつかの回文(上から読んでも下から読んでも同じ並びになる数)の和として表すために必要な回文の最小個数を求める問題です。例えば、N = 15の場合、15 = 8 + 7 と表現できるため、必要な回文の個数は2となります。アルゴリズムの考え方この問題は次の2つのステップで解くことができます。N以下のすべての回文を昇順に生成する和がちょうどNになるような最小の部分集合のサイズを求める後半のステップはいわゆる「部分和問題」の一種であり、メモ化再帰(動的計画法)を用いることで効率的に解けます。回文の効率的な生成方法すべての数値に対して回文かどうかを1つずつ判定する
-
C++で最初のn個の自然数の総和の合計を求める方法
問題の概要本記事では、「最初のn個の自然数の総和の合計」を求める問題を扱います。具体的には、1からnまでの各自然数kについて「1からkまでの合計」を計算し、それらをすべて足し合わせた最終的な値を求めます。まず、具体例を見ながら概念を理解しましょう。入力 : 4 出力 : 20 説明 : 最初の1個の自然数の合計 = 1 最初の2個の自然数の合計 = 1 + 2 = 3 最初の3個の自然数の合計 = 1 + 2 + 3 = 6 最初の4個の自然数の合計 = 1 + 2 + 3 + 4 = 10 したがって、総和の合計 = 1 + 3 + 6 + 10 = 20このように、各段階の部分和(1, 3