Project Euler 32
7254は面白い性質を持っている. 39 × 186 = 7254と書け, 掛けられる数/掛ける数/積に1から9の数が1回ずつ出現する. 掛けられる数/掛ける数/積に1から9の数が1回ずつ出現するような積の総和を求めよ. HINT: いくつかの積は, 1通り以上の掛けられる数/掛ける数/積の組み合わせを持つが1回だけ数え上げよ.
Mathematica
ans = {}; For[i = 1, i <= 10000, i++, For[j = i, j <= 10000, j++, tmp = i*j; If[tmp>10000, Break[]]; A = Sort[ Flatten[{IntegerDigits[i], IntegerDigits[j], IntegerDigits[tmp]}]]; If[A == Table[i, {i, 9}] && MemberQ[ans, i*j] == False, Print[{i, j, i*j}]; ans = Append[ans, i*j]; , {}] ] ]
まあ10000までループさせる必要なんかないですけどね。
10000の2重ループはとても危険な感じがしますが、
If[tmp>10000, Break[]];
の1行がうまく効いてくれてます。
C/C++
#include <iostream> #include <deque> #include <set> using namespace std; // xを各桁ごとにばらしてdequeに挿入する。 deque<int> integerDigit(int x){ deque<int> arr; while(x!=0){ arr.push_front(x%10); x/=10; } return arr; } // m, n, mn がpandigital(1から9が1回ずつ出現する)かどうかを判定する。 bool isPandigital(int m, int n, int mn){ deque<int> num1, num2, num3; set<int> nums; num1 = integerDigit(m); num2 = integerDigit(n); num3 = integerDigit(mn); for(int i=0 ; i < (signed)num1.size() ; i++){ nums.insert(num1[i]); } for(int i=0 ; i < (signed)num2.size() ; i++){ nums.insert(num2[i]); } for(int i=0 ; i < (signed)num3.size() ; i++){ nums.insert(num3[i]); } int s = nums.size(); if(s != num1.size() + num2.size() + num3.size()) return false; set<int>::iterator it = nums.begin(); if(s==9 && *it!=0) return true; else return false; } int main(){ set<int> nums; for(int i=1; i<100 ; i++){ for(int j=i ; j<10000 ; j++){ if(i*j>10000) continue; if(isPandigital(i,j,i*j)){ cout << i << "*" << j << "=" << i*j << endl; nums.insert(i*j); } } } int sum=0; set<int>::iterator it = nums.begin(); for(int i=0 ; i<(signed)nums.size() ; i++){ sum += *it; it++; } cout << "sum -> " << sum << endl; }
問題読んだ時点ではうわー、めんどくさーい・・・と思いましたが、やってみたら別段苦労する部分もなく。
冗長ですがそこまで遅いわけでもありません。