Project Euler

Project Euler 問題32(パンデジタル積)を解いてみる

760x428_Euler_032

Project Euler で紹介されている問題32を解いてみました。ライブラリで順列を使える C++ を利用して解きました。

Project Euler 問題32(パンデジタル積)

n桁の数で、1からnまでのすべての数字をちょうど1回ずつ使うものをパンディジタル(pandigital)と呼ぶことにする。たとえば、5桁の数 15234 は1から5のパンディジタルである。

掛けられる数、掛ける数、積の式、39×186=7254 が1から9のパンデジタルとなっている。7254はその積である。

掛けられる数/掛ける数/積が、1から9のパンデジタルとなる式の積の和を求めよ。

ヒント:いくつかの積は、いくつかの方法で得ることができるが、積の和としては、一度だけ含まれるようにしてください。

解答例

Project Euler 問題24(辞書式順列)で順列について紹介しました。Project Euler では、C を使って解くことが多かったですが、C では標準ライブラリで順列のサポートがありません。標準ライブラリで順列のサポートがあるC++を使って解きます。

順列を生成する next_permutataion を do-while と組みにして、1から9までのすべての順列を生成します。

この順列を、sep1、sep2 という切れ目で、3つの数字に分割します。配列のインデックスを使って表現すると3つの数字は以下となります。以下、[n, m) は、「n以上、m未満」を表します。

  • 掛けられる数 num1 = [0, sep1)
  • 掛ける数 num2 = [sep1, sep2)
  • 積 num3 = 「sep2, 9)

また、複数の方法で同じ積を得ることができるため、set を使って重複を取り除いています。具体的な C++ プログラムは、以下となります。

#include <iostream>
#include <algorithm>
#include <set>

using namespace std;

int main(void)
{
	int n[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
	set<int> p;

	do {
		int sep1, sep2;
		for (sep1 = 1; sep1 <= 7; ++sep1) {
			for (sep2 = sep1 + 1; sep2 <= 8; ++sep2) {
				int num1 = 0;
				int num2 = 0;
				int num3 = 0;
				for (int i = 0; i < sep1; ++i) {
					num1 = num1 * 10 + n[i];
				}
				for (int i = sep1; i < sep2; ++i) {
					num2 = num2 * 10 + n[i];
				}
				for (int i = sep2; i < 9; ++i) {
					num3 = num3 * 10 + n[i];
				}
				if (num1 * num2 == num3) {
//					printf("%d * %d = %d\n", num1, num2, num3);
					p.insert(num3);
				}
			}
		}
	} while (next_permutation(n, n + 9));

	int sum = 0;
	for (auto it = p.begin(); it != p.end(); ++it) {
		sum += *it;
	}

	printf("Problem032: %d\n", sum);

	return 0;
}

コメントアウトしている printf を有効にすると、見つけた式を表示します。以下の積は複数の式で見つかりました。

  • 12 × 483 = 138 × 42 = 5796
  • 18 × 297 = 198 × 27 = 5346

最後に

順列のライブラリサポートがあれば、それほど難しくない問題でした。試してみると、上で紹介したように、積が同じになる複数の式が見つかりました。このような計算でも数の不思議を感じました。

引き続き、Project Euler の問題を紹介していきます。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA