C#
数学パズル

C#で数学パズル - 小町数で3つの式の値を等しくする

小町数を使った数学パズルの第3弾です。

問題

「○○ − ○ = ○○ / ○ = ○ + ○ × ○ 」の○の部分に、1から9までの数がひとつずつ入るようにせよ。
真ん中の式は、割り切れる数にすること。

どうやて解くか

いわゆる小町数パズルのひとつです。

意外と難しいです。紙と鉛筆で解こうと試行錯誤してみましたが、僕は答えがわかりませんでした。

この問題を解くには、基本的には、総当たりで調べてゆくプログラムを書けば良いですね。
それには、1から9までの数のすべての順列を求めて、その順列に対し、式が成り立つかを調べれば答えを求めることができます。
例えば、求めた順列が、3,5,6,9,8,2,1,4,7 ならば、35 - 6 = 98 / 2 = 1 + 4 * 7 という式が成り立つかを調べればいいですね。

つまり、順列を求めるプログラムが書ければ、それを少し変形することで、この問題を解くプログラムを書くことができます。

ということで、「C#:全ての要素を使った順列を求める」に掲載した順列を求めるクラスPermutationを利用して、問題を解こうと思います。

求めた順列の一つ一つに対して、「○○ー○ = ○○ / ○ = ○ + ○ × ○ 」に当てはめて、式が成り立つかを調べます。

C#:全ての要素を使った順列を求める」で掲載しているコードをブラックボックスとして捉えれば、それほど難しいことをやっているわけではありません。
IskomachiExpなんて、力技のコードなので、もうすこしスッキリ書きたいなとは思ったのですが...

C#のコード

順列を求めるPermutationクラスのコードも、最後に載せておきます。

public class Solver {
    public IEnumerable<int[]> Solve() {
        var nums = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        return _Solve<int>(nums);
    }

    private IEnumerable<int[]> _Solve<T>(IEnumerable<int> nums) {
        var perm = new Permutation();
        foreach (var n in perm.Enumerate(nums)) {
            var array = n.ToArray();
            if (IskomachiExp(array))                    
                yield return array;
        }
    }

    // 「○○ー○ = ○○ / ○ = ○ + ○ × ○ 」が成り立つかを調べる
    // nums.Length は9であることが保証されている
    private bool IskomachiExp(int[] nums) {
        var a = nums[0] * 10 + nums[1];
        var b = nums[2];
        var x = a - b;
        var c = nums[3] * 10 + nums[4];
        var d = nums[5];
        var y = c / d;
        if (x != y)
            return false;
        if (y * d != c) // yは切り捨てされるので、ここで、再度チェック
            return false;
        var e = nums[6];
        var f = nums[7];
        var g = nums[8];
        if (x != e + f * g)
            return false;
        return true;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var sol = new Solver();
        foreach (var nums in sol.Solve()) {
            string s = $"答えは、{nums[0]}{nums[1]}-{nums[2]} = " +
                $"{nums[3]}{nums[4]}/{nums[5]} = {nums[6]}+{nums[7]}*{nums[8]} です。";
            Console.WriteLine(s);
        }
    }
}

以下に示すのは、C#:全ての要素を使った順列を求めるに掲載した順列を求めるPermutationクラス

public class Permutation {
    public IEnumerable<T[]> Enumerate<T>(IEnumerable<T> items) {
        return _GetPermutations<T>(new List<T>(), items.ToList());
    }

    private IEnumerable<T[]> _GetPermutations<T>(IEnumerable<T> perm, IEnumerable<T> items) {
        if (items.Count() == 0) {
            yield return perm.ToArray();
        } else {
            foreach (var item in items) {
                var result = _GetPermutations<T>(perm.Concat(new T[] { item }),
                                                    items.Where(x => x.Equals(item) == false)
                                );
                foreach (var xs in result)
                    yield return xs.ToArray();
            }
        }
    }

    internal int[] ToArray() {
        throw new NotImplementedException();
    }
}

結果

答えは、37-8 = 29/1 = 5+4*6 です。
答えは、37-8 = 29/1 = 5+6*4 です。

2つの答えが出ましたが、最後の2つの数が入れ替わっただけなので、実質的に答えはひとつということになりますね。


この記事は、Gushwell's C# Programming Pageで公開したものをに加筆・修正したものです。