fork(1) download
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4.  
  5. my @DATA;
  6. while(<DATA>) { # Получение входных данных и запуск рабочей процедуры на них
  7. @DATA = split /\s+/;
  8. next if @DATA < 3; # Не обрабатываем строки с менее чем 3 элементами
  9. work();
  10. }
  11.  
  12. sub work {
  13. # Массив позиций разделителей с дополнительныйми элементами по краям
  14. # для контроля по ним выходов за границы массива (сокращает количество проверок границ)
  15. # Содержит начало данных, левый разделитель (после первого элемента),
  16. # правый разделитель (второй с конца), конец данных
  17. my $border = [ 0, 1, @DATA-1, @DATA-0 ];
  18. # Текущие суммы разделенных частей массива, в тех же элементах (по номеру) что и позиции границ
  19. my $sum = [ 0, $DATA[0], 0, $DATA[$border->[2]] ];
  20. # Вычисляем сумму элементов средней части (массива без крайних элементов)
  21. $sum->[2]+=$_ for @DATA[1..$border->[2]-1];
  22. # Рабочий цикл, боюсь делать while(1)
  23. for(1..1000) {
  24. my $ch = change($border, $sum, 1) + # Двигаем левый разделитель
  25. change($border, $sum, 2); # Двигаем правый разделитель
  26. last unless $ch; # Завершаем цикл если ни одна граница не двигалась
  27. }
  28. # Печать результата
  29. print join('+', @DATA[0..$border->[1]-1]), "=$sum->[1] // ";
  30. print join('+', @DATA[$border->[1]..$border->[2]-1]), "=$sum->[2] // ";
  31. print join('+', @DATA[$border->[2]..@DATA-1]), "=$sum->[3]\n";
  32. }
  33.  
  34. sub change {
  35. # Движение одного разделителя в сторону "улучшения равномерности сумм"
  36. # Параметры: Описания границ, Текущие суммы, Номер разделителя
  37. my($border, $sum, $pos) = @_;
  38. my $n1 = $sum->[$pos]; # Сумма левее разделителя
  39. my $n2 = $sum->[$pos+1]; # Сумма правее разделителя
  40. # Получаем направление движения границы +1 вправо, -1 влево
  41. # Если суммы одинаковы, направление 0 - выходим
  42. (my $sign = $n2 <=> $n1) || return 0;
  43. my $i = $border->[$pos]; # Текущая позиция в массиве данных
  44. # Выходим если движение в нужную сторону не возможно, так как упираемся в другой разделитель
  45. return 0 if $border->[$pos+$sign] == $i+$sign;
  46. my $oldDelta = abs($n1 - $n2); # Текущая разница сумм
  47. if($sign > 0) { # движение вправо
  48. $n1 += $DATA[ $i ];
  49. $n2 -= $DATA[ $i ];
  50. } else { # движение влево
  51. $n1 -= $DATA[ $i-1 ];
  52. $n2 += $DATA[ $i-1 ];
  53. }
  54. my $newDelta = abs($n1 - $n2); # Новая разность сумм
  55. # print "pos: $pos [$border->[$pos]], sign: $sign n1: $n1, n2: $n2 nD: $newDelta, oD: $oldDelta\n";
  56. return 0 if $newDelta >= $oldDelta; # Выходим ничего не меняя, если результат не улучшился
  57. # Движение в выбранную сторону улучшает результат, сохраняем новые суммы и позицию
  58. $sum->[$pos] = $n1;
  59. $sum->[$pos+1] = $n2;
  60. $border->[$pos]+=$sign;
  61. return 1;
  62. }
  63. __DATA__
  64. 1 2 3 100
  65. 1 2 3 100 101 102 140
  66. 4 4 4 4
  67. 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
  68. 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 200 1 1
  69.  
  70.  
Success #stdin #stdout 0.01s 5348KB
stdin
Standard input is empty
stdout
1+2=3 // 3=3 // 100=100
1+2+3+100=106 // 101+102=203 // 140=140
4=4 // 4+4=8 // 4=4
1+1+1+1+1+1+1=7 // 1+1+1+1+1+1+1+1=8 // 1+1+1+1+1+1+1=7
1+1+1+1+1+1+1+1+100=108 // 1+1+1+1+1+1+1+1+1+1=10 // 200+1+1=202