Posted at

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

More than 1 year has passed since last update.

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