Problem43
30分プログラム、その316。Problem43 - Project Euler。
数1406357289は0から9のPandigital数である (0から9が1度ずつ現れるので). この数は部分語が面白い性質を持っている.
d1を1桁目, d2を2桁目の数とし, 以下順にdnを定義する. この記法を用いると次のことが分かる.
- d2d3d4=406は2で割り切れる
- d3d4d5=063は3で割り切れる
- d4d5d6=635は5で割り切れる
- d5d6d7=357は7で割り切れる
- d6d7d8=572は11で割り切れる
- d7d8d9=728は13で割り切れる
- d8d9d10=289は17で割り切れる
このような性質をもつ0から9のPandigital数の総和を求めよ.
2の倍数、3の倍数、...、17の倍数をあらかじめ用意しておいて、それの組み合せで作れるPandigital数を求めるようにした。
そのために、倍数をリストにいれるようにしたんだけれども、Perlでリスト操作はやるもんじゃないね。入れ子のリストが使えないのは本当に不便だ。
使い方
$ perl problem43.pl Name "main::b" used only once: possible typo at problem43.pl line 81. Name "main::a" used only once: possible typo at problem43.pl line 81. 16695334890
ソースコード
#! /usr/bin/perl # -*- mode:perl; coding:utf-8 -*- # # problem43.pl - # # Copyright(C) 2008 by mzp # Author: MIZUNO Hiroki / mzpppp at gmail dot com # http://howdyworld.org # # Timestamp: 2008/06/01 21:01:18 # # This program is free software; you can redistribute it and/or # modify it under MIT Lincence. # use strict; use warnings; use List::Util qw(reduce sum); use Data::Dumper; sub make($){ my ($n) = @_; my @xs = (); for(my $i = 0; $i < 1000/$n;$i++){ my $m = $n*$i; if($m =~ /\A(\d)(\d)(\d)\Z/ and ($1 != $2 and $2 != $3 and $2 != $3)){ @xs = (@xs,[$1,$2,$3]); }elsif($m =~ /\A(\d)(\d)\Z/ and ($1 != $2)){ @xs = (@xs,[0,$1,$2]); } } @xs; } sub is_connect($$){ my ($x,$y) = @_; @$x[-2] == @$y[0] and @$x[-1] == @$y[1]; } sub conn(@){ if(@_ > 1){ my ($x,@xs) = @_; my $y = &conn(@xs); my @ys = (); for my $n (@$x){ for my $m (@$y){ if(is_connect($n,$m)){ @ys = (@ys,[@$n[0],@$m]) } } } [@ys]; }else{ $_[0]; } } sub is_pandigital(@){ my %xs = (); for(@_){ if(defined $xs{$_}){ return 0; }else{ $xs{$_} = 1; } } defined $xs{0}; } sub make_pandigital(@){ my %xs = (); for(@_){ $xs{$_} = 1; } for(1..9){ unless(defined $xs{$_}){ return reduce {$a * 10 + $b } ($_,@_); } } } my @ds = map { [ make($_) ] } (2,3,5,7,11,13,17); my @xs = @{conn(@ds)}; my @ys = grep { is_pandigital @$_ } @xs; my @zs = map { make_pandigital @$_ } @ys; print sum(@zs),"\n";