作者: 閑舎
日時: 2002/5/13(10:41)
 今回は汎用性を考えて解いたもの……と言いたかったが、すでに順列生成の関
数が TSperl に流れているので、あまり独自性がなくなってしまった。まあ、せっ
かく作ったので出します(^^;。dune さんのと同じように実行でき、同じ結果が
戻ります。

--------^ ticket4.pl ( date:02-05-13 time:08:00 ) ----------< cut here
#! env perl
### 初期化
my $num = "8 4 2 1";
my $op = "+ - * /";
my $target = 10;
my $opn = $num =~ s/\s+/ /g;
my @num = mkary("", $num);
my @op = mkary2("", $op, $opn);

### 数値と演算子を組み合わせる、実際の処理部分
for (my $i = 0; $i < @num; $i++) {
  for (my $j = 0; $j < @op; $j++) {
    my $exp = $num[$i];
    $exp =~ s/ /substr($op[$j], $_, 1)/e foreach (0 ... ($opn - 1));
    printf("$exp=%d\n", eval($exp)) if (eval($exp) == $target);
  }
}

### $post の要素から作られる全順列を、配列の形で返す
### "1 2 4 8", "1 4 2 8", ...
sub mkary {
  my ($pre, $post, @ary) = @_;
  return (@ary, $pre) if ($post =~ /^\s*$/);
  foreach (split(/\s+/, $post)) {
    my $post1 = $post;
    $post1 =~ s/$_\s*//;
    @ary = mkary(($pre eq "")? $_: "$pre $_", $post1, @ary);
  }
  return @ary;
}

### $str から n 個、重複を許して取り出し、並べたものを配列の形で返す
### "+++", "++-", ...
sub mkary2 {
  my ($exp, $str, $n, @ary) = @_;
  return (@ary, $exp) if ($n == 0);
  @ary = mkary2(($exp eq "")? $_: "$exp$_", $str, $n - 1, @ary) foreach (split(/\s+/, $str));
  return @ary;
}
--------$ ticket4.pl ( lines:39 ) --------------------------< cut here

myary2 は上で使うのに一番手軽なように、空白をつめたものを返してますが、
この辺は空白入れるのも、文字列の配列で返すのをやめて配列の配列にするのも
少し手を入れれば可能ですから、まあ汎用的と言えるかと思います。

--
本田博通(閑舎)
Hiromichi Honda <raku@...>