Настройте мой код для решения головоломки

#performance #perl #puzzle

#Производительность #perl #Головоломка

Вопрос:

5 обезьян разделяют n персиков, они не могут распределяться равномерно. Итак, первая обезьяна сбросила 1 персик, а общее количество персиков можно разделить на 5, и первая обезьяна приняла участие.

Тогда вторую обезьяну, -1 персик, можно разделить на 5 и принять его участие. Пока пятая обезьяна не закончила все шаги. Возможно, еще осталось немного персиков.

Укажите минимальное количество персиков, удовлетворяющих этому условию.

perl код 1:

 #!/usr/bin/perl -w
for $n (0..10000){      #this is basic idea but code is too messy !
    if( ($n-1) % 5 == 0 ){
     $remain = 4/5 * ($n -1 );
         if( ($remain - 1) % 5 == 0){
           $remain = 4/5 * ($remain -1 );
           if( ($remain - 1) % 5 == 0){
               $remain = 4/5 * ($remain -1 );
               if( ($remain - 1) % 5 == 0){
                   $remain = 4/5 * ($remain -1 );
                   if( ($remain - 1) % 5 == 0){
                      $remain = 4/5 * ($remain -1 );
                      print "remain: $remain original: $nn";
                   }
               }
            }
          }
     }
 }
  

perl code 2:

 sub doit($){
    ($n) = @_;
    if( ($n - 1) % 5 ==0 ){ #if can be distributed by 5 monkey
       $n = ($n - 1) * 4/5;  #commit distribute
       return $n;
    }else{
       return -1;  #fail
    }
}

for $n (0..10000){   #restriction
    $r = $n;    #"recursively" find solution
    $o = $n;    #backup n
    $count = 0;
    for ($i = 0; $i < 5; $i  ){  #assume there is 5 monkey, it can be changed
       $r = doit($r);
    if($r == -1){   #skip once fail
        last;
    }
    $count  ;
    }
    if($count == 5){ # if pass 5 test, then you found the number !
       print "now ".$r."n";
       print "origin ".$o."n";
    }
}
  

Я подумываю сократить некоторый код. Но чувствовал себя тяжело. Кто-нибудь может помочь?

Комментарии:

1. во-первых, вы не используете строгие предупреждения и!

2. Этот вопрос не заслуживает отрицательных голосов. По сравнению со всеми публикациями «покажите мне код», CodeFarmer дважды попробовал это сделать. Тем не менее, не мешало бы добавить лучшее описание вверху.

3. Да, я проголосовал против этого из-за действительно пугающего глобального использования, но позже передумал, потому что это действительно хороший вопрос. Проблема в том, что это не позволяет мне отменить голосование!

4. @Joel: Просто чтобы вы знали, вы можете отредактировать вопрос (ничего не меняя), чтобы разблокировать отрицательные голоса и удалить свой. Возможно, это вызовет неодобрение, я не знаю — но это лучше, чем позволить незаслуженному снижению голосов, если вы передумали.

5. @cHao, спасибо, мне действительно пришлось кое-что изменить, чтобы это заняло больше времени, но никто не заметит пробел, который я добавил в конце абзаца!

Ответ №1:

Прежде всего, вам действительно следует использовать strict и warnings pragmas в верхней части ваших сценариев. Ваше $n использование вызывает особую тревогу. В будущем, если вы объявляете переменные с my , но используете одно и то же имя, вы передаете тот факт, что они будут представлять одинаковое количество, без опасения, что они могут столкнуться.

В любом случае, вот слегка отшлифованная и, что более важно, strict и warnings безопасная версия:

 #!/usr/bin/env perl

use strict;
use warnings;

sub doit {
    my ($n) = @_;
    if( ($n - 1) % 5 ==0 ){ #if can be distributed by 5 monkey
       $n = ($n - 1) * 4/5;  #commit distribute
       return $n;
    } else {
       return undef;  #fail
    }
}

OUTER: for my $n (0..10000){   #restriction
    my $r = $n;    #"recursively" find solution
    for (1..5){  #assume there is 5 monkey, it can be changed
       $r = doit($r);
       next OUTER unless defined $r;
    }
    # if code gets here, then it passed 5 test, then you found the number !
    print "now: $rtorigin: $nn";
}
  

А теперь, если вы действительно хотите получить от этого удовольствие (не используйте это в производстве, сначала удобочитаемость!):

 #!/usr/bin/env perl

use strict;
use warnings;

OUTER: for my $n (0..10000){ 
    my $r = $n;
    $r = ($r - 1) % 5 ? next OUTER : 4/5 * ($r - 1) for (1..5);
    print "now: $rtorigin: $nn";
}
  

или даже играли в гольф:

 for(0..10000){$r=$n=$_;map$r*=--$r%5?next:4/5,1..5;print"now: $rtorigin: $nn"}
  

Ответ №2:

Рассмотрим это решение:

 sub share {
  ($_[0] - 1) % 5 == 0 ? ($_[0]-1)/5*4 : die "unable to share";
}

for my $i (1..10000) {
  eval {
    share(share(share(share(share($i)))));
  };
  unless ($@) {
    print "solution: $in";
    last;
  }
}
  

Я уверен, что внутри скрывается монада.

Ответ №3:

Я не уверен на 100%, что понимаю ваш вопрос, но вместо того, чтобы искать ответ, начните с последней обезьяны. Минимальное количество персиков, которое он мог бы взять, равно 1, и даже если их может остаться немного, чтобы получить минимум, предположим, что осталось 0. Теперь подсчитайте, сколько персиков увидела предпоследняя обезьяна, и так далее.

Нет необходимости в цикле, если вы начинаете с последней обезьяны

  # set numPeaches to what the last monkey had
 $numPeaches = 1;

 # then, figure out how many the second to last monkey had, and add to numPeaches

 # and, so on ...

 # until you get to the first monkey
  

Комментарии:

1. да, я знаю, я просто хочу попробовать что-нибудь написать, чтобы решить проблему. Последним остатком персиков может быть любое число, большее 0, в данном случае минимальное число равно 3121, после того, как пятый забрал свою часть, все равно остаются тысячи