JP / EN
Insights / Algorithm

Make 10 の数理と実装

なぜ「全探索」が最もエレガントな証明になるのか?
ファームウェアエンジニアの視点で解く、数遊びのアルゴリズム。

1. ナンバープレートの脳内パズル

車を運転しているとき、前を走る車のナンバープレートが気になってしまうことはありませんか? 特に、4つの数字がバラバラ(すべて異なる数字)だった時、私の脳内では自動的にある処理が走り始めます。

「この4つの数字を四則演算(+, -, ×, ÷)して、10を作れ」

いわゆる「Make 10(テンパズル)」と呼ばれる遊びです。 私は昔からこれが得意で、信号待ちで前の車を見かけた瞬間、ほぼ反射的に解法が浮かびます。例えば「1, 3, 7, 9」なら $(7+3) \times (9-1) \div 8$ ...いや、もっと単純に $(9-7) \times (1+3) + \dots$ といった具合に、瞬時に式を組み立ててしまいます。

経験則として、「1から9までの異なる4つの数字」を選んだ場合、解けない組み合わせに出会うことはまずありません。 では、これを数学的に証明することはできるでしょうか? 「異なる4つの数字を選べば、必ず10が作れる」という命題を、$x$ や $y$ を使った美しい数式で証明しようとすると、意外な壁にぶつかります。

2. 代数学の敗北:演算子は変数になれない

通常、数学の証明といえば、代数的な変形を思い浮かべます。 しかし、Make 10 の難しさは、数字($a, b, c, d$)だけでなく、「演算子($+, -, \times, \div$)」と「計算順序(カッコ)」そのものが変数である点にあります。

一般的な方程式 $f(x) = 10$ のような形では、演算子の組み合わせという「構造の変化」を表現しきれません。 連続的な数値の変化を扱う解析学(微分積分など)のアプローチは、このような離散的(飛び飛び)な構造に対しては無力なのです。

3. エンジニアの解法:「全探索」という証明

ここで登場するのが、私たちエンジニアが得意とするアルゴリズム的アプローチです。 数式で一般化できないのなら、「有り得るすべてのパターンをしらみつぶしに検証(Proof by exhaustion)」してしまえばいいのです。

「美しくない」と思われるでしょうか? いいえ、これこそが離散数学における最も強力で確実な証明です。

  • 数字の組み合わせ: 1~9から異なる4つを選ぶ(${}_9C_4$) = 126通り

たったの126通りです。 それぞれの組み合わせに対して、演算子と順序(逆ポーランド記法などの木構造)の全パターンを適用しても、コンピュータにとっては瞬きする間もない計算量です。

これはファームウェア開発における「状態遷移テスト」と同じ考え方です。 無限の入力があるアナログ回路とは異なり、デジタルシステム(離散系)は状態が有限であるため、「全網羅」こそが最強の品質保証(証明)となります。

4. 検証コード(C言語)

論より証拠。実際にC言語でソルバーを書き、全126通りを検証してみました。 以下のコードは、再帰探索(DFS)を用いて数値を縮約しながら、可能なすべての演算パターンを探索するプログラムです。

/**
 * Make 10 Solver & Prover
 * Author: Dr. WataWata (M.A.L.)
 * Description: Verifies that all combinations of 4 distinct digits (1-9) can make 10.
 */
#include <stdio.h>
#include <math.h>
#include <stdbool.h>

#define TARGET 10.0
#define EPSILON 1e-6

// 再帰的に演算を行う関数 (Depth First Search)
bool can_make_10(double nums[], int n) {
    if (n == 1) {
        return fabs(nums[0] - TARGET) < EPSILON;
    }

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (i == j) continue;

            double next_nums[4];
            int m = 0;
            
            for (int k = 0; k < n; k++) {
                if (k != i && k != j) next_nums[m++] = nums[k];
            }

            double a = nums[i];
            double b = nums[j];

            // Addition
            next_nums[m] = a + b;
            if (can_make_10(next_nums, n - 1)) return true;

            // Subtraction
            next_nums[m] = a - b;
            if (can_make_10(next_nums, n - 1)) return true;

            // Multiplication
            next_nums[m] = a * b;
            if (can_make_10(next_nums, n - 1)) return true;

            // Division
            if (fabs(b) > EPSILON) {
                next_nums[m] = a / b;
                if (can_make_10(next_nums, n - 1)) return true;
            }
        }
    }
    return false;
}

int main() {
    int count = 0;
    int success_count = 0;
    
    printf("Exploring all combinations of 4 distinct digits from 1-9...\n");

    for (int i = 1; i <= 9; i++) {
        for (int j = i + 1; j <= 9; j++) {
            for (int k = j + 1; k <= 9; k++) {
                for (int l = k + 1; l <= 9; l++) {
                    
                    count++;
                    double initial_set[4] = {(double)i, (double)j, (double)k, (double)l};
                    
                    if (can_make_10(initial_set, 4)) {
                        success_count++;
                    } else {
                        printf("[FAIL] %d, %d, %d, %d -> Impossible\n", i, j, k, l);
                    }
                }
            }
        }
    }

    printf("------------------------------------------------\n");
    printf("Total combinations tested: %d\n", count);
    printf("Solvable combinations:     %d\n", success_count);
    
    if (count == success_count) {
        printf("Result: PROVED. All distinct combinations can make 10.\n");
    } else {
        printf("Result: DISPROVED.\n");
    }

    return 0;
}

このプログラムを実行すると、Result: PROVED が出力され、「1~9の異なる4つの数字」の組み合わせ全126通りにおいて、解が存在することが数学的(計算機的)に証明されます。

5. Dr.WataWata Insight

「数式で解けない」ということは、決して「数学的ではない」ということではありません。 有限の離散構造において、計算機(アルゴリズム)を用いた全探索は、立派な数学的証明の一つです。

私が車のナンバープレートを見て瞬時に「10」を作れるのは、私の脳内に高性能なCPUがあるわけではなく、「解が存在することは数学的に保証されている」という安心感が、直感を支えているからなのかもしれません。

次に前の車のナンバーが「異なる4つの数字」だったら、安心して挑んでみてください。必ず答えはそこにありますから。