LoginSignup
1
0

More than 5 years have passed since last update.

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

Posted at

小町数を使った数学パズルの第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で公開したものをに加筆・修正したものです。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0