46

Приём ответов завершён, всем спасибо за участие!
Можете оставлять свои решения, но победители уже выбраны и пересчёта не будет.


Приветствую.

Задача: Напишите функцию, которая из произвольного входящего массива выберет все комбинации чисел, сумма которых будет равняться 10.

Подробнее:
Диапазон чисел: 0 - 1000 включительно.
Количество чисел во входящем массиве: 1 - 10 включительно.
Уже выбранные числа могут использоваться неоднократно, но комбинации должны быть уникальны.
--- Смена позиций не делает комбинацию уникальной, т. е. [1,9] и [9,1] не позволяются).
--- При входных данных [5,5,2,3] можно сделать [5,5], [5,2,3].
Продолжительность конкурса: 14 дней.
Обязательный формат метки ответа (для автоматического парсера в таблицу):
<h2>Язык, КоличествоСимволов</h2>

Определение победителя: Определяется по градации:

  1. Реализация, состоящая из наименьшего количества символов.
  2. Реализация, получившая больше всего плюсов (общий рейтинг минус голоса против).
  3. Реализация, время первой редакции которой раньше.

Необходимо так же давать ссылку на один из онлайн-компиляторов с Вашим рабочим кодом.
Тесты приветствуются.
Настоятельно рекомендуется давать как конкурсную версию кода (минифицированную и/или с колдунствами), так и наглядное описание этого же кода. Всем интересно не только увидеть языковую магию, но и что-то почерпнуть для себя.

От одного участника допустимо несколько ответов, если они реализованы на разных языках. Но не более одного на язык


Все вопросы по деталям и/или разногласиям и/или трактовке условий, прошу обсуждать в комментариях к этому сообщению или в комнате чата по код-гольфу.


Итоги:

Стандартные 3 места + 1 за самое большое количество плюсов (общий рейтинг минус голоса против).

1 место: @PavelMayorov - Haskell, 42 символа.
2 место: @ArtemKonovalov - Scala, 69 символов.
3 место: @Mike - Perl, 78 символов.

Зрительские симпатии: @D-side (Ruby, 84) - 19 баллов.

Поздравления всем участникам, вы хорошо сражались.
Особенно страсти накалились в самом конце, когда неожиданно было опубликовано решение обгоняющее лидера на 1 символ.
Но судьба вернула всё обратно.

Хотелось бы отметить необычное для данного соревнования решение от пользователя @AlexanderGavrikov - 1437 символов!
Это своеобразный рекорд, стоит отметить.


Таблица лидеров:

execute(581668);
.cssload-container,.cssload-cube{width:97px;height:97px;transform-style:preserve-3d}.cssload-container,.cssload-cube,.cssload-half1,.cssload-half2{transform-style:preserve-3d}.cssload-container{position:relative;margin:23px 84px;perspective:292px}.cssload-cube{animation:cube 11.5s forwards infinite;transform-origin:center 49px}.cssload-half1,.cssload-s1{top:0;transform-origin:50% 100%}.cssload-half1{height:39px;position:absolute;animation:half-fold 11.5s forwards infinite}.cssload-side{width:19px;height:19px;background:#ddd;position:absolute}.cssload-s1{left:39px;animation:s1ani 11.5s forwards infinite}.cssload-s2,.cssload-s3,.cssload-s4{left:39px;transform-origin:50% 0}.cssload-s2{top:19px;animation:s2ani 11.5s forwards infinite}.cssload-s3{top:39px;animation:s3ani 11.5s forwards infinite}.cssload-s4{top:58px;animation:s4ani 11.5s forwards infinite}.cssload-s5{left:19px;top:19px;transform-origin:100% 50%;animation:s5ani 11.5s forwards infinite}.cssload-s6{left:58px;top:39px;transform-origin:0 50%;animation:s6ani 11.5s forwards infinite}@keyframes cube{0%,30%{transform:rotateX(0)}40%{transform:rotateX(45deg) rotateY(0) rotate(45deg)}60%{transform:rotateX(60deg) rotateY(0) rotate(45deg)}65%,70%{transform:rotateX(60deg) rotate(45deg) rotate(180deg)}75%,80%{transform:rotateX(60deg) rotate(45deg) rotate(1turn)}90%{transform:rotateX(0) rotate(0) rotate(0)}}@keyframes s1ani{0%{opacity:1;transform:translateY(0);background:#ddd}40%{transform:rotateX(0);background:#ddd}50%{transform:rotateX(-90deg);background:#ddd}90%{transform:rotateX(-90deg)}}@keyframes s2ani{0%{opacity:0;transform:rotateX(-179deg)}10%{opacity:1;transform:rotateX(0)}40%{background:#ddd}45%,80%{background:#b4b4b4}65%{opacity:1;background:#b4b4b4}90%{opacity:1}to{opacity:0}}@keyframes s3ani{0%,10%{opacity:0;transform:rotateX(-179deg)}20%,90%{opacity:1;transform:rotateX(0)}40%{background:#ddd}45%{background:#969696}to{opacity:0}}@keyframes s4ani{0%,20%{opacity:0;transform:rotateX(-179deg)}10%,to{opacity:0}30%{opacity:1;transform:rotateX(0)}40%{transform:rotateX(0);background:#ddd}50%{transform:rotateX(90deg);background:#b4b4b4}80%{background:#b4b4b4}90%{opacity:1;transform:rotateX(90deg)}}@keyframes s5ani{0%,10%{opacity:0;transform:rotateY(-179deg)}20%{opacity:1;background:#ddd;transform:rotateY(0)}40%{transform:rotateY(0)}50%{transform:rotateY(90deg)}55%{background:#ddd}60%{background:#c8c8c8}90%{transform:rotateY(90deg);opacity:1}to{opacity:0}}@keyframes s6ani{0%,20%{opacity:0;transform:rotateY(179deg)}30%{opacity:1;transform:rotateY(0)}40%{transform:rotateY(0)}50%{transform:rotateY(-90deg);background:#ddd}60%,80%{background:#c8c8c8}90%{opacity:1;transform:rotateY(-90deg)}to{opacity:0}}@keyframes half-fold{0%,50%{transform:rotateX(0)}60%,90%{transform:rotateX(-90deg)}}

.cssload-container,.cssload-cube{width:97px;height:97px;transform-style:preserve-3d}.cssload-container,.cssload-cube,.cssload-half1,.cssload-half2{transform-style:preserve-3d}.cssload-container{position:relative;margin:23px 84px;perspective:292px}.cssload-cube{animation:cube 11.5s forwards infinite;transform-origin:center 49px}.cssload-half1,.cssload-s1{top:0;transform-origin:50% 100%}.cssload-half1{height:39px;position:absolute;animation:half-fold 11.5s forwards infinite}.cssload-side{width:19px;height:19px;background:#ddd;position:absolute}.cssload-s1{left:39px;animation:s1ani 11.5s forwards infinite}.cssload-s2,.cssload-s3,.cssload-s4{left:39px;transform-origin:50% 0}.cssload-s2{top:19px;animation:s2ani 11.5s forwards infinite}.cssload-s3{top:39px;animation:s3ani 11.5s forwards infinite}.cssload-s4{top:58px;animation:s4ani 11.5s forwards infinite}.cssload-s5{left:19px;top:19px;transform-origin:100% 50%;animation:s5ani 11.5s forwards infinite}.cssload-s6{left:58px;top:39px;transform-origin:0 50%;animation:s6ani 11.5s forwards infinite}@keyframes cube{0%,30%{transform:rotateX(0)}40%{transform:rotateX(45deg) rotateY(0) rotate(45deg)}60%{transform:rotateX(60deg) rotateY(0) rotate(45deg)}65%,70%{transform:rotateX(60deg) rotate(45deg) rotate(180deg)}75%,80%{transform:rotateX(60deg) rotate(45deg) rotate(1turn)}90%{transform:rotateX(0) rotate(0) rotate(0)}}@keyframes s1ani{0%{opacity:1;transform:translateY(0);background:#ddd}40%{transform:rotateX(0);background:#ddd}50%{transform:rotateX(-90deg);background:#ddd}90%{transform:rotateX(-90deg)}}@keyframes s2ani{0%{opacity:0;transform:rotateX(-179deg)}10%{opacity:1;transform:rotateX(0)}40%{background:#ddd}45%,80%{background:#b4b4b4}65%{opacity:1;background:#b4b4b4}90%{opacity:1}to{opacity:0}}@keyframes s3ani{0%,10%{opacity:0;transform:rotateX(-179deg)}20%,90%{opacity:1;transform:rotateX(0)}40%{background:#ddd}45%{background:#969696}to{opacity:0}}@keyframes s4ani{0%,20%{opacity:0;transform:rotateX(-179deg)}10%,to{opacity:0}30%{opacity:1;transform:rotateX(0)}40%{transform:rotateX(0);background:#ddd}50%{transform:rotateX(90deg);background:#b4b4b4}80%{background:#b4b4b4}90%{opacity:1;transform:rotateX(90deg)}}@keyframes s5ani{0%,10%{opacity:0;transform:rotateY(-179deg)}20%{opacity:1;background:#ddd;transform:rotateY(0)}40%{transform:rotateY(0)}50%{transform:rotateY(90deg)}55%{background:#ddd}60%{background:#c8c8c8}90%{transform:rotateY(90deg);opacity:1}to{opacity:0}}@keyframes s6ani{0%,20%{opacity:0;transform:rotateY(179deg)}30%{opacity:1;transform:rotateY(0)}40%{transform:rotateY(0)}50%{transform:rotateY(-90deg);background:#ddd}60%,80%{background:#c8c8c8}90%{opacity:1;transform:rotateY(-90deg)}to{opacity:0}}@keyframes half-fold{0%,50%{transform:rotateX(0)}60%,90%{transform:rotateX(-90deg)}}

/* TODO: Fix it */ body { font-size: 1rem; line-height: 1.5rem; font-family: 'Open Sans', sans-serif; background: #fff; padding: 0 2rem; }

h1 { font-weight: 600; margin-bottom: 3rem; text-align: center; color: #212121; }

#leadership { width: 100%; margin: 1rem auto;
border-collapse: collapse; box-shadow: 0 2px 7px rgba(0,0,0,0.2); background: #fafafa; }

#leadership td { padding: 1rem .5rem !important; text-align: left; font-weight: 500; transition: all .3s ease-in-out; }

#leadership tr:hover td{ background: #03a9f4; color: #fefefe; }

#leadership tr:hover td a { color: #fff; }

#leadership th { padding: 1.5rem .5rem !important; color: #727272; text-align: left !important; font-weight: 500; border-bottom: 1px solid #dcdcdc; }

#leadership a { text-decoration: none; color: #212121; }

#leadership a:hover { color: #03a9f4; }

#leadership td:nth-of-type(1){ text-align: center; color: #727272; font-size: .75rem; }

#leadership td:nth-of-type(2){

}

#leadership td:nth-of-type(2) img { width: 34px; border-radius: 50%; }

/* #leadership th:nth-of-type(1), #leadership th:nth-of-type(2){ border-bottom: none; } */

#leadership th:nth-of-type(5), #leadership th:nth-of-type(6), #leadership th:nth-of-type(7), #leadership td:nth-of-type(5), #leadership td:nth-of-type(6), #leadership td:nth-of-type(7) { text-align: center !important; }

<script src="https://mayorovp.github.io/codegolf/97314479fcd24a2386e1.js"></script>
<div class=cssload-container><div class=cssload-cube><div class=cssload-half1><div class="cssload-side cssload-s1"></div><div class="cssload-side cssload-s2"></div><div class="cssload-side cssload-s5"></div></div><div class=cssload-half2><div class="cssload-side cssload-s3"></div><div class="cssload-side cssload-s4"></div><div class="cssload-side cssload-s6"></div></div></div></div>

Удачи всем!

  • а ограничения по времени есть? + Что считать разными комбинациями (позиции или значения) – pavel Oct 23 '16 at 10:49
  • @pavel, да, 14 дней с момента начала. Позиции не важны, главное чтобы комбинации были уникальны. –  Oct 23 '16 at 10:50
  • по времени работы... – pavel Oct 23 '16 at 10:51
  • @pavel, время работы алгоритма в разумных пределах, но потолка нет. –  Oct 23 '16 at 10:54
  • где можно посмотреть на ответы? – spectre_it Oct 23 '16 at 11:08
  • 2
    @stas0k, как только ответы будут даны, их список можно увидеть тут в качестве ответов или в таблице лидеров вопроса. –  Oct 23 '16 at 11:09
  • "Уже выбранные числа могут использоваться неоднократно" - из 5,2,3 можно выбрать 5,5? – Qwertiy Oct 23 '16 at 20:20
  • а куда сортировка пропала? вроде ж была – Grundy Oct 24 '16 at 06:25
  • @Grundy, что-то было, пофиксил. –  Oct 24 '16 at 07:54
  • @Qwertiy, разрешено повторять в разных комбинациях. В текущей - уже выбрано число, больше нельзя. –  Oct 24 '16 at 07:56
  • Зачем диапазон 0..1000, когда сумма всего лишь 10? – αλεχολυτ Oct 25 '16 at 04:44
  • @alexolut, чтобы фильтровать такие числа, если нужно. –  Oct 25 '16 at 10:14
  • "Первое место в качестве приятного бонуса получает награду конкурса." - это вы за меня решили, кто награду получает? – Nick Volynkin Nov 06 '16 at 16:24
  • @NickVolynkin, так вроде награда передаётся принятому ответу. Да и логично это. Или у Вас есть идея получше? Я слушаю. –  Nov 06 '16 at 22:20
  • @Other награда передаётся принятому ответу только когда инициатор конкурса "пропал". А так - какой выберу, тому и передаётся, моя же награда. )) – Nick Volynkin Nov 07 '16 at 08:33
  • @NickVolynkin, не знал :) Тогда просто положусь на Вашу проницательность. –  Nov 09 '16 at 15:52

15 Answers15

26

Ruby, 84 91

->a{(1..a.size).flat_map{|n|a.sort.combination(n).select{|c|c.reduce(:+)==10}.uniq}}

Первое решение, которое таки умещается в одну строку при просмотре с сайта!

Это литерал лямбды, который надо вызвать с массивом входных данных. Результатом будет массив из найденных комбинаций.

Ideone

В Ruby функция получения комбинаций элементов массива реализована прямо в классе Array, в стандартной библиотеке. Ой.

В остальном, решение максимально прямое и неплохо переводится на естественный язык:

(1..a.size)              # Для диапазона от 1 до длины массива А
  .flat_map{ |n|         # ...сконкатенировать для каждого N в нём следующее:
    a.sort               #   Из отсортированного массива А...
     .combination(n)     #   ...взять все комбинации длиной N элементов
     .select{ |c|        #   ...выбрав только те С из них, в которых:
       c.reduce(:+)==10} #     Cвёртка С сложением равна 10.
     .uniq}              #   ...убрав повторения.

Поскольку порядок в комбинациях неважен, чтобы не получить дубликатов, массив можно отсортировать. Можно отсортировать и комбинации постфактум, но это медленнее и требует больше символов.

24

Haskell, 42 70 символа

g=nub.filter((10==).sum).subsequences.sort

Требует импорта функций nub, sort и subsequences из Data.List

Запуск: main = print $ g [5,5,2,3] http://ideone.com/5jUIsy

Как работает:

  • входной список сортируется (иначе функция nub, см. далее, не поймет);
  • функция subsequences находит все сочетания (без ограничения длины), их 2m, где m - длина входного списка;
  • при помощи filter выбираются те сочетания, которые дают нужную сумму;
  • при помощи nub выбираются различные сочетания.

PS спасибо участнику Artem Konovalov за то, что опосредованно подсказал мне не писать велосипед, а заглянуть в стандартную библиотеку языка :)

Pavel Mayorov
  • 58,537
  • Разместите код в онлайн и в рабочем виде, пожалуйста. Со всеми импортами и функциями. –  Oct 24 '16 at 08:30
  • 4
    Интересно, а разве импорты считать в длину не надо ? Ведь так сейчас можно готовую библиотеку для какого нибудь языка найти, которая делает то что нужно ... – Mike Oct 24 '16 at 08:34
  • @Mike это системная библиотека. На том же C# юзинги и объявления класса тоже традиционно не учитываются. – Pavel Mayorov Oct 24 '16 at 08:36
  • @Mike, встроенное, "из коробки" не считается. –  Oct 24 '16 at 08:41
  • хаскель в гольфе вне конкуренции, это точно, даже читерский combination не спас руби, это потому что combination длинно) – Гончаров Александр Oct 24 '16 at 10:52
  • @ГончаровАлександр на самом деле, вне конкуренции специальные языки, созданные для гольфа :) – Pavel Mayorov Oct 24 '16 at 10:55
  • @Pavel Mayorov но это уж будут реализации совсем далекие от реалий, а хаскель и в бою используют – Гончаров Александр Oct 24 '16 at 11:07
  • "(напишет 2) " - что значит напишет два? два варианта ответа? – 4per Oct 24 '16 at 21:39
  • @4per ничего не значит. Сначала я другую задачу решал, осталось случайно :) – Pavel Mayorov Oct 25 '16 at 03:11
  • А что, импорты не включаются в подсчёт количества символов? – Nick Volynkin Nov 06 '16 at 18:16
  • @NickVolynkin из стандартной библиотеки - нет – Pavel Mayorov Nov 06 '16 at 18:16
  • @PavelMayorov жесткая типизация скалы не позволила написать короче( – Artem Nov 06 '16 at 18:24
  • @ArtemKonovalov а в Хаскеле типизация тоже жесткая :) – Pavel Mayorov Nov 06 '16 at 18:51
  • Ну и наконец награда за первое место ) – Nick Volynkin Nov 15 '16 at 17:46
23

SQL SQLite Oracle 11.2, 104 114 124 147 176

обнаружен баг (см.комментарии)

Реализация алгоритма выборки комбинации слагаемых для получения заданной суммы из заданного набора значений, с помощью рекурсивных SQL-запросов

  • Решение на конкурс
 WITH t(p,w,s)AS(SELECT'',0,0 UNION SELECT p||i||';',r,i+s FROM t,a WHERE r>w)SELECT p FROM t WHERE s=10;
  • Подготовка
-- создаём таблицу с данными
CREATE TABLE a (r INTEGER, i INTEGER);

-- заполняем INSERT INTO a VALUES (1,5); INSERT INTO a VALUES (2,5); INSERT INTO a VALUES (3,2); INSERT INTO a VALUES (4,3);

  • Читаемый вариант решения
    в конкурсном убраны алиасы. вместо t.r - w, a.r - r, a.i - i
WITH t (p, r, s) AS
  (SELECT '', 0, 0 -- инициализация кортежа для рекурсии
   UNION
   SELECT 
     p || a.i || ';' , -- сбор строки для вывода
     a.r, -- запоминаем номер строки, чтоб не взять дважды    
     a.i+s -- накопительная сумма
   FROM t, a
   WHERE a.r > t.r -- ограничение - не использовать уже учтенные строки 
  ) 
SELECT p -- вывод комбинаций
FROM t 
WHERE s = 10; --наше конкурсное условие - сумма=10
  • Выдача
P
5;5;
5;2;3;   
4per
  • 2,696
19

perl, 78  &nbsp&nbsp81 95 98 109 112 118 121 123 178

use List::Util 'sum';  # В размере не учитывается - библиотека "из коробки"

sub X{for$c(sort@_){@r=map{$_,[@$_,$c]}@r,[]}grep{!$f{"@$_"}++&&10==sum@$_}@r}

Тест на ideone.com

Не сжатый вариант:

sub X{
 for $c(sort@_) {             # Перебираем отсортированный входной массив
  @r=map {$_,[@$_,$c]} @r,    # Для каждого элемента в массиве вариантов добавляем
                              # такой же но с добавленным текущим числом
                          []  # Затравка первого цикла - пустой массив
 }
 grep {                       # Выбираем те элементы массива
       !$f{"@$_"}++ &&        # Которые еще не встречались ранее
       10==sum@$_             # И сумма элементов которых равна 10
      } @r
}

Старый вариант с рекурсией (95 символов):

sub X {                              # Основная функция
  my$n=pop;                          # $n=первый параметр (текущий остаток)
 @_=sort@_;                          # Сортируем входной массив
 my %r;                              # Объявляем хеш результатов
 map {                               # перебираем массив
  my$a=$n-(my$c=pop);                # вытаскиваем очередной элемент массива (в $c)
                                     # и вычисляем текущий остаток минус данный элемент массива
    $r{"$c,$_"}++ for X(@_,$a)       # Кладем в хеш результатов каждый элемент массива,
                                     # который вернет функция перед которым текущий элемент с запятой
  $r{$c}++ if!$a                     # Если разность 0 - то кладем в результаты само число
 } @_;
 keys%r                              # возвращаем массив результатов
}

# Вызов    
@A=(1,3,4,5,3,3,7,2,7,10);           # Тестовый массив
$,="\n";
print X(@A,10);
Mike
  • 44,087
  • Позвольте узнать: 1) Что это $#_+1? Ясно что итератор, как? 2) Как заполняется push @r,"$c,$_" for X($a,@_)? Благодарю. –  Oct 23 '16 at 17:42
  • @Other 1. параметры функции в perl содержатся в массиве @_, количество элементов минус 1 в этом массиве (индекс последнего элемента) это $#_. изначально я написал $#_>=0 но это на 1 символ длиннее $#_+1. А вот первый shift внутри цикла берет первый элемент массива и сдвигает массив. 2. предположим у нас $c=5, а функция X для остатка массива вернет массив значений [5, "3,2", "2,2,1"] тогда for пробежит по этому массиву и создаст строки "$c,5" (т.е. "5,5"), "5,3,2", "5,2,2,1" собственно эти строки и будут положены в массив @r. – Mike Oct 23 '16 at 17:57
  • @Other Кстати, заменил shift на pop, он короче и забирает элемент из конца массива, а не из начала, на суть алгоритма не влияет. И исправил ошибку, if($a>0) стало if($a>=0), а то иначе если в конце массива нули, они не обрабатывались – Mike Oct 23 '16 at 18:13
  • @Other Кажется я понял, что вас с for смутило. Если вы с perl не сталкивались, то выполнение строки справа налево выглядит конечно непривычно. В других языках эта строка была бы что то вроде for($_ in X($a,@_)) { push(@r, $c+","+$_) } – Mike Oct 23 '16 at 18:22
  • Исчёрпывающе, благодарю. –  Oct 24 '16 at 08:07
  • Все, у меня теперь без шансов ) – Nofate Oct 25 '16 at 10:21
  • @Nofate, не печальтесь, у Вас признание зрителей :) –  Oct 25 '16 at 10:26
  • @Nofate Ну мне вчера 112 казалось последним пределом, оказалось есть что выжимать. – Mike Oct 25 '16 at 10:26
19

JavaScript, 163 148 141 129 124 118 109 92

байткод для конкурса :) Совместное творчество с @Mike .

f=(n,s,c,r=[],i=0)=>{for(s?0:c[r.join()]=r;i<n.length;)f(n,s-n[i],c,[n[i],...r].sort(),++i)}

Пояснения к коду:

var input = prompt('Введите цифры через запятую, к примеру 5,5,2,0,3,4,10,2,56,2,0,8');
input = input ? input.split(',').map(function(v){return parseInt(v);}) : [];

f=(n/входной массив чисел/, s/желаемая сумма/, c/выходные данные/, r=[]/слагаемые - промежуточная переменная/, i=0/текущий шаг - промежуточная переменная/)=>{ /запуск рекурсии, которая обойдёт все комбинации чисел в массиве , комбинация на каждом шаге в аргументе r , (желаемая_сумма - сумма_комбинации) : в аргументе s/ for( s?0:c[r.join()]=r;/если сумма == 0 - записываем слагаемые в выходные данные/ i<n.length;/рекурсия останавливается, когда доходим до последнего элемента/ ) f(n, s-n[i]/вычитаем из суммы текущий элемент массива/ ,c ,[n[i],...r].sort()/добавляем в слагаемые текущий элемент массива, сортируем для уникальности/ ,++i/повторяем операцию для следующего элемента массива/) }

var output = {}; f(input, 10, output); alert('Комбинации, дающие 10: ' + Object.keys(output).join('; '));

Тест обфускации:

var input = prompt('Введите цифры через запятую, к примеру 5,5,2,0,3,4,10,2,56,2,0,8');
input = input ? input.split(',').map(function(v){return parseInt(v);}) : [];

f=(n,s,c,r=[],i=0)=>{for(s?0:c[r.join()]=r;i<n.length;)f(n,s-n[i],c,[n[i],...r].sort(),++i)}

var output = {}; f(input, 10, output); alert('Комбинации, дающие 10: ' + Object.keys(output).join('; '));

P.S. Вариант для конурса имеет избыточные аргументы для краткости:
Вторым аргументом необходимо передать желаемую сумму, в нашем случае 10.
Третий аргумент - объект, в который запишется результат, экономия на return надеюсь разрешена)

  • 1
    109: f=(n,s,r=[],c={},i=0)=>{s||(c[r.join(',')]=r);for(;i<n.length;)f(n,s-n[i],[n[i],...r].sort(),c,++i);return c} при вызове вторым параметром передаем желаемую сумму – Mike Oct 25 '16 at 17:44
  • @Mike крутяк, добавь ответ, мне рука не позволит воспользоваться чужими улучшениями :) – Гончаров Александр Oct 26 '16 at 10:12
  • А у меня рука не поднимется писать его как свое, ибо я не знаю на столько JS что бы написать ...r и даже такое краткое объявление функции для меня совершенно в новинку. Ну а небольшие перестановки сделать, по следам допилки моего perl решения ... это именно небольшие улучшения :) – Mike Oct 26 '16 at 10:29
  • @Mike хорошо, будет совместным творчеством) – Гончаров Александр Oct 26 '16 at 10:50
19

R, 111

s<-function(a)unique(Filter(function(x)sum(x)==10,unlist(Map(function(n)combn(a,n,sort,F),c(1:length(a))),F)))

Код на IDE ONE

Человекопонятный код:

solve <- function(a) {
  # собираем вектор с допустимыми длинами комбинаций
  sizes <- c(1:length(a)) 
  # сопоставляем каждой длине комбинации, получаем список списков комбинаций, каждая комбинация пропускается через sort
  combinations <- Map(function(size) combn(a, size, FUN = sort, simplify = FALSE), sizes)
  # делаем список с комбинациями плоским
  combinations <- unlist(combinations, recursive = FALSE)
  # оставляем только комбинации дающие в сумме 10
  combinations <- Filter(function(x) sum(x) == 10, combinations)
  # выкидываем дубликаты
  combinations <- unique(combinations)
  #возвращаем результат
  combinations
}

Вызывется на интересующем векторе

s(c(2,3,5,5))
Nofate
  • 34,603
  • Однозначно плюс. Только сжатый и подробный листинги отличаются, можно узнать что творится в конкурсном решении? –  Oct 24 '16 at 18:13
  • Там то же самое, только без промежуточных переменных – Nofate Oct 24 '16 at 18:18
  • грубо говоря, a <- f(g(x)) я расписал как a <- g(x); a <- f(a) – Nofate Oct 24 '16 at 18:19
18

PHP, 114   120 127 130 131 132 143 151 140 142 145 149 163 171 172

По количеству так-же, но выдает меньше предупреждений и работает быстрее.

function($a,&$o){for(;2e3-$c++;$d&=$t=[])foreach($a as$k=>$e)1<<$k&$c?:($d+=$t[]=$e)-sort($t)-9?:$o[join($t)]=$t;}

sandbox

function($a, &$o){
    for(; 2e3 - $c++; $d &= $t = [])                 // Перебор битовых масок массива 0..1023(2000)
        foreach($a as $k => $e)
            1<<$k&$c                                 // Попадает ли элемент в маску?
                ?: ($d += $t[] = $e) - sort($t) - 9  // sort() == 1,  ($d += $t[] = $e) == $d
                    ?: $o[ join($t) ] = $t;          // join совместно с sort обеспечивают уникальность
}
rjhdby
  • 13,850
  • Боюсь, в гольфе только одна реализация от одного участника. Удалите одну реализацию, пожалуйста. –  Oct 27 '16 at 11:10
  • Обычное требование для гольфа. Для и для всех, наверное, подобных конкурсов - вариантов можете делать сколько хотите, но на конкурс только один. –  Oct 27 '16 at 11:19
  • 1
    @Other впервые слышу о таком. Была просьба от модераторов "не публикуйте несколько ответов на один вопрос (если нет веских причин)", но в соревнованиях как раз часта ситуация, когда один участник участвует разными решениями на нескольких языках или существенно разными способами (да я и сам так делал). Здесь, впрочем, не тот случай. –  Oct 27 '16 at 11:54
  • @D-side, не спорю - у каждого свои правила. Мне ближе этот стиль. Пока нет официальных правил, которые все приняли, приходится обходится своими. Решение проблемы с глобальными правилами будет скоро обсуждаться мой в чате гольфа. –  Oct 27 '16 at 11:59
  • 1
    @Other, нет таких правил. Можно сколько угодно. – Qwertiy Oct 27 '16 at 22:47
  • @Qwertiy, см. условие в вопросе. А список правил создаётся. –  Oct 28 '16 at 05:48
  • @Other, ну дописал ты - и что с того? – Qwertiy Oct 28 '16 at 06:25
  • @Qwertiy, как что? Следовать надо этим правилам значит. –  Oct 28 '16 at 07:46
  • PHP проигрывает своим долларом перед переменными) – Гончаров Александр Oct 28 '16 at 19:21
15

Python3, 130         131 136 144 147 168 182 216 226

Минифицированный вариант:

def r(a,c=[],z=[]):
 a.sort()
 for i,v in enumerate(a):z+=[c+[v]]if v+sum(c)==10*0**(c+[v]in z)else r(a[i+1:],c+[v],z)*0
 return z

Пример использования:

res = r( [1,4,5,5,2,3,1,4] )
print( res )

Минифицированная версия исключительно для гольфа.


Не минифицированная версия:

def recur( arr, curArr, maxSumm ):
    arr.sort()
    curSumm = sum( curArr ) # текущая набранная сумма, не забываем, что sum([]) == 0
    result = []
    for i in range( len( arr ) ):
        if arr[i] + curSumm == maxSumm: # если в сумме набрали нужное число, то добавляем к результату
            result+=[ curArr + [ arr[i] ] ]
        elif arr[i] + curSumm < maxSumm: # если сумма меньше, то добавляем результат рекурсивного вызова
            result+= recur( arr[i+1:], curArr + [ arr[i] ], maxSumm )
    return result

def unique( arr ): # уникальные значения массива
    unique = []
    [ unique.append(i) for i in arr if i not in unique ]
    return unique

Живой пример:
http://ideone.com/ggl9lO

ReinRaus
  • 17,873
  • 3
  • 47
  • 86
  • Да, я этот вопрос там обнаружил поэтому и удалил комент :) – Mike Oct 23 '16 at 21:31
  • Сделал жесткую минификацию, но не смог стать короче Perl ^( Ну почему в Python нет нормальной функции unique :) – ReinRaus Oct 23 '16 at 22:25
  • Ну в перле без библиотек ее то же нет и ее реализация никак не короче вашей минифицированной :) – Mike Oct 23 '16 at 22:42
  • Python обогнал Вас :) – ReinRaus Oct 23 '16 at 22:55
  • О, обогнал мой js'ный вариант :) Кстати, старое количество символов вроде принято зачёркивать? – Qwertiy Oct 23 '16 at 23:27
  • вариант с PHP догнал :) – rjhdby Oct 29 '16 at 13:35
15

Javascript ES6, 165 161 150 147 145 134 133 125 123 (неверно) 124 118

a=>[...Array(2e3)].map((x,q)=>a.filter((x,i)=>q&1<<i).sort()).sort().filter((x,i,a)=>x+""!=a[i-1]&eval(x.join`+`)==10)

Примечания:

  1. Длина массива ограничена 10 числами, поэтому можно использовать перебор по маске.
  2. Лямбда-функция не рекурсивная, поэтому её сохранение в переменную не учитывается в числе символов. Подробнее на codegolf'е.
  3. Текущая версия функции не создаёт глобальных переменных

Проверка:

f=a=>[...Array(2e3)].map((x,q)=>a.filter((x,i)=>q&1<<i).sort()).sort().filter((x,i,a)=>x+""!=a[i-1]&eval(x.join`+`)==10)

console.log(f([5,5,2,3]).join(" ")) console.log(f([5,2,3]).join(" ")) console.log(f([0,10,10,5,0]).join(" ")) console.log(f([0,10,10,5,0,5]).join(" ")) console.log(f([9]).join(" "))

Qwertiy
  • 123,725
  • Мне кажется, если я правильно понял задачу - у тебя не проходит условие уникальности. – Гончаров Александр Oct 23 '16 at 23:45
  • @ГончаровАлександр, а поточнее? Желательно с примером. – Qwertiy Oct 23 '16 at 23:49
  • @ReinRaus, ## и <h2> - это одно и то же. Сниппет надо подправить, чтоб зачёркнутое игнорировал. – Qwertiy Oct 23 '16 at 23:51
  • Да он вообще Вас игнорирует :) – ReinRaus Oct 23 '16 at 23:51
  • @ReinRaus, я его уже исправил :) – Qwertiy Oct 23 '16 at 23:58
  • мож я чего не понимаю, но 2;3;5 два раза показывается – 4per Oct 24 '16 at 00:00
  • @4per, для какого инпута? В сниппете выводятся результаты 4 тестов, в двух из них по одному разу встречается 2,3,5. – Qwertiy Oct 24 '16 at 00:01
  • @Qwertiy, ну теперь понятно – 4per Oct 24 '16 at 00:07
  • @Qwertiy, всё хорошо, сори. Совсем круто было бы, если бы ты добавил необфусцированную версию кода! – Гончаров Александр Oct 24 '16 at 00:58
  • @ГончаровАлександр, я её прям так писал - вроде несложная :) – Qwertiy Oct 24 '16 at 07:04
  • @Qwertiy, всё же опишите поэтапно код функции. –  Oct 24 '16 at 08:54
  • Что-то ошибку выдает при попытке запустить – rjhdby Oct 27 '16 at 10:22
  • @rjhdby, смени IE на что-нибудь нормальное? У меня в хроме всё работает. http://kangax.github.io/compat-table/es6/ – Qwertiy Oct 27 '16 at 10:26
  • у меня хром. Жму кнопку "выполнить код" и вываливает ошибку. { "message": "Uncaught SyntaxError: Unexpected token =>", "filename": "http://stacksnippets.net/js", "lineno": 13, "colno": 12 } – rjhdby Oct 27 '16 at 11:05
  • @rjhdby, нужен Chrome 49+. Желательно даже 52+, потому что мне лень разбираться детально по поддержке. Но описанная ошибка может быть только в Chrome 44-. См. раздел arrow functions по ссылке в комментарии выше. И ещё destructing. – Qwertiy Oct 27 '16 at 11:15
  • @rjhdby, ну как, получилось запустить? – Qwertiy Oct 28 '16 at 07:55
  • @Qwertiy неа. Кровавый энтерпрайз вынуждает использовать "Версия 43.0.2357.132 m". Буду страдать. – rjhdby Oct 28 '16 at 08:57
  • @rjhdby, а FF или Edge? Или дома?)) – Qwertiy Oct 28 '16 at 09:00
  • @Qwertiy не, кровавый энтерпразй такой кровавый. А дома жена и дети, как-то не до стека :) – rjhdby Oct 28 '16 at 09:49
11

Scala, 69 73, 80

Нечитабельный вариант:

def f(a:Seq[Int])=a.indices.flatMap(a.combinations).filter(_.sum==10)

пример использования

val a = List(1,2,3,4,5,6,7,8,9,10)
println(f(a))

Читабельный вариант:

def getSeq(list: List[Int]) =
 list
  //берем индексы т.е. получаем последовательность от 0 до size
  .indices
  //берем всевозможные комбинации длиной index из элементов списка
  .flatMap(index => list.combinations(index))
  //фильтруем списки по сумме элементов == 10
  .filter(s => s.sum == 10)

Демка

Artem
  • 14,967
8

C++, 174 152

using m=multiset<int>;set<m>f(auto a){set<m>r;for(int q=2e3,s;--q;){m c;s=10;for(int&x:a)if(q&1<<&x-&a[0])c.insert(x),s-=x;if(!s)r.insert(c);}return r;}

Примечания:

  • В качестве аргумента следует передавать контейнер, в котором элементы лежат последовательно.

http://ideone.com/4AAo0T http://ideone.com/o1nsmz

#include <iostream>
#include <set>
#include <vector>

using namespace std;

//set<multiset<int>>f(vector<int>a){set<multiset<int>>r;for(int q=2e3,s;--q;){multiset<int>c;s=0;for(auto&x:a)if(q&1<<&x-&a[0])c.insert(x),s+=x;if(s==10)r.insert(c);}return r;} //174
//using m=multiset<int>;set<m>f(vector<int>a){set<m>r;for(int q=2e3,s;--q;){m c;s=0;for(auto&x:a)if(q&1<<&x-&a[0])c.insert(x),s+=x;if(s==10)r.insert(c);}return r;} //161
//using m=multiset<int>;set<m>f(auto a){set<m>r;for(int q=2e3,s;--q;){m c;s=0;for(auto&x:a)if(q&1<<&x-&a[0])c.insert(x),s+=x;if(s==10)r.insert(c);}return r;} // 155
//using m=multiset<int>;set<m>f(auto a){set<m>r;for(int q=2e3,s;--q;){m c;s=0;for(int&x:a)if(q&1<<&x-&a[0])c.insert(x),s+=x;if(s==10)r.insert(c);}return r;} // 154
//using m=multiset<int>;set<m>f(auto a){set<m>r;for(int q=2e3,s,i;--q;){m c;s=i=0;for(int&x:a)if(q&1<<i++)c.insert(x),s+=x;if(s==10)r.insert(c);}return r;} // 153
//using m=multiset<int>;set<m>f(auto a){set<m>r;for(int q=2e3,s,i;--q;){m c;s=10,i=0;for(int&x:a)if(q&1<<i++)c.insert(x),s-=x;if(!s)r.insert(c);}return r;} // 153
  using m=multiset<int>;set<m>f(auto a){set<m>r;for(int q=2e3,s;--q;){m c;s=10;for(int&x:a)if(q&1<<&x-&a[0])c.insert(x),s-=x;if(!s)r.insert(c);}return r;} // 152
//using m=multiset<int>;set<m>f(auto a){set<m>r;m c;for(int q=2e3,s;--q;!s?r.insert(c),0:0){c.clear();s=10;for(int&x:a)if(q&1<<&x-&a[0])c.insert(x),s-=x;}return r;}

int main()
{
    for (auto &r : f((vector<int>){5,5,2,3}))
    {
        for (auto &x : r)
            cout << x << ' ';

        cout << '\n';
    }

    return 0;
}
Qwertiy
  • 123,725
  • Наконец-то :) Правда сжатый код в пояснении таким же и остался, а смысл как раз в пояснении. –  Nov 03 '16 at 21:41
  • @Other, это не пояснение, а тест. И я его сейчас продолжаю ужимать. Уже 152 получилось :) – Qwertiy Nov 03 '16 at 21:48
  • У Вас сейчас 152 символа, но можно на один уменьшить, заменив multiset на list, а insert на push_back. – αλεχολυτ Nov 06 '16 at 13:25
  • @alexolut, нельзя. Они кладутся в сет, поэтому любой неупорядоченный контейнер позволит выводить одинаковые наборы с разным порядком чисел. Так что либо sort, либо multiset. А ещё у меня сейчас 151, а не 152. Или я неверно посчитал? – Qwertiy Nov 06 '16 at 20:25
  • Вот замена, которую я предлагал и вычисление длины строки. Перепроверьте свои расчеты. – αλεχολυτ Nov 07 '16 at 09:37
  • @alexolut, Вот форк с другим интпутом - поменял {5,5,2,3} на {5,2,5,3} - работает неверно. Нужно обеспечить отсортированность чего-нибудь. – Qwertiy Nov 07 '16 at 09:58
  • @alexolut, количество символов пересчитал. Действительно на 1 ошибся :( – Qwertiy Nov 07 '16 at 10:01
  • Кстати, если уж говорить про символы, то надо и using namespace std; со всеми необходимыми #include учитывать. – αλεχολυτ Nov 07 '16 at 11:00
7

Java, 1437

Всем добрый день. Не уверен, есть ли однозначность в условии, но насколько я понимаю, если входной массив {2, 3, 5, 5, 0}, то в результате должно быть 4 строки: {2, 3, 5}, {0, 2, 3, 5}, {5, 5}, {0, 5, 5}. Так как массивы {2, 3, 5} и {0, 2, 3, 5} отличаются один {0}, но массивы разные и их сумма равна 10. В некоторых решениях выше при вводе данных {2, 3, 5, 5, 0} ответ будет только из двух массивов {2, 3, 5} и {5, 5}. Написано, Что во входном файле числа от 0 до 1000 включительно, значит нули могут быть.

Написал свое решение на Java. Оно по сравнению с другими очень громоздкое, однако не хранит список массивов в памяти, чтобы удалять дубликаты, а выводит их "на лету", что называется. Плюс учитывает тот случай, который рассмотрел выше. Большой объем кода еще объясняется написание без использования каких-то стандартных коллекций. Идея в том, чтобы подсчитать количество единиц, двоек, троек и т. д. десяток во входном файле. Зная эту информацию, а также количество нулей, построить ответ.

Рабочий код тут: http://ideone.com/mwV9Uh

Листинг решения:

import java.util.Scanner;
public class Main {
    int c[] = new int[11];
    void f(int n, int s, int[] cc) {
        for (int i = 1; i <= c[n]; ++i) {
            cc[n] += i;
            s += i * n;
            if (s == 10) {
                for (int z = 0; z <= c[0]; ++z) {
                    for (int j = 0; j < z; ++j) {
                        System.out.print("0 ");
                    }
                    for (int j = 1; j <= 10; ++j) {
                        for (int k = 0; k < cc[j]; ++k) {
                            System.out.print(j + " ");
                        }
                    }
                    System.out.println("");
                }
            }
            if (s >= 10) {
                cc[n] -= i;
                return;
            }
            for (int m = n + 1; m <= 10; ++m) {
                f(m, s, cc);
            }
            s -= i * n;
            cc[n] -= i;
        }
   }
   void g() {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            int x = scanner.nextInt();
            if (x >= 0 && x <= 10) {
                c[x]++;
            }
            if (x == -1) {
                break;
            }
        }
        int[] cc = new int[11];
        for (int i = 1; i <= 10; ++i) {
            f(i, 0, cc);
        }
   }
   public static void main(String[] args) {
        Main x = new Main();
        x.g();
   }
}

Вот пример читаемого кода:

    import java.util.Scanner;

    public class Main {

        //количество каждого числа от 0 до 10 во входном файле
        int cnt[] = new int[11];

        //вывод массива на экран
        private void printArray(int[] curCnt) {
            for (int i = 1; i <= 10; ++i) {
                for (int j = 0; j < curCnt[i]; ++j) {
                    System.out.print(i + " ");
                }
            }
            System.out.println();
        }

        //перебор для вывода вариантов
        private void brute(int number, int curSum, int[] curCnt, int tab) {
            for (int i = 1; i <= cnt[number]; ++i) {
                curCnt[number] += i;
                curSum += i * number;
                if (curSum == 10) {
                    for (int cntZero = 0; cntZero <= cnt[0]; ++cntZero) {
                        for (int i_ = 0; i_ < cntZero; ++i_) {
                            System.out.print("0 ");
                        }
                        printArray(curCnt);
                    }
                }
                if (curSum >= 10) {
                    curCnt[number] -= i;
                    return;
                }
                for (int newNumber = number + 1; newNumber <= 10; ++newNumber) {
                    brute(newNumber, curSum, curCnt, tab + 1);
                }
                curSum -= i * number;
                curCnt[number] -= i;
            }
        }

        private void run() {
            //считывание данных из консоля
            Scanner scanner = new Scanner(System.in);
            while (scanner.hasNext()) {
                int x = scanner.nextInt();
                if (x >= 0 && x <= 10) {
                    cnt[x]++;
                }
                if (x == -1) {
                    break;
                }
            }
            int[] cntCur = new int[11];


      for (int i = 1; i <= 10; ++i) {
            brute(i, 0, cntCur, 0);
        }
    }

    public static void main(String[] args) {

        Main solution = new Main();
        solution.run();
    }
}
  • "В большинстве решений выше при вводе данных {2, 3, 5, 5, 0} ответ будет только из двух массивов {2, 3, 5} и {5, 5}." - у меня все 4, у ответа, опубликованного до меня было тоже все 4. Но вообще где-то в чате говорилось, что можно нули игнорировать. – Qwertiy Nov 06 '16 at 00:21
  • Идея в целом хорошая, я думал про такой подход, но пришёл к выводу, что он очень плохо ужимается, а это соревнование помечено как гольф. В решении можно было замерять только функцию, а не весь код. Кроме того, не видно никаких усилий по минификации - огромное число необязательных фигурных скобок, а так же отступы и переводы строк (которые можно было оставить, но с пометкой, что они не учитывались в подсчёте символов). Стоит взглянуть на комментарии тут. – Qwertiy Nov 06 '16 at 00:28
  • Кстати, рад видеть тебя в этом соревновании (что-то не сразу обратил внимание на плашку с автором). Загляни в соседнее - может на джаве тоже решение придумаешь, а то её до полного комплекта не хватает :) – Qwertiy Nov 06 '16 at 00:41
  • "В большинстве решений выше при вводе данных {2, 3, 5, 5, 0} ответ будет только из двух массивов {2, 3, 5} и {5, 5}." - стоит перечислить их. – Pavel Mayorov Nov 06 '16 at 05:59
  • Например решение на С++, вот сделал форк http://ideone.com/9Zvk – Alexander Gavrikov Nov 06 '16 at 11:18
  • Корректная ссылка тут http://ideone.com/9Zvkmv – Alexander Gavrikov Nov 06 '16 at 11:20
  • @Alexander Gavrikov Эм.. Там данные не считываются, в коде захардкожено f((vector<int>){5,5,2,3}), писать в stdin то же с ноликом несколько бесполезно ;) – Qwertiy Nov 06 '16 at 20:22
7

D, 110

import std.stdio;
import std.array;
import std.range;
import std.algorithm;

alias f=e=>e.permutations.map!"a.length.iota.map!(b=>a[0..b+1].array.sort)".join.sort.filter!"a.sum==10".uniq;

void main()
{
    [5, 5, 2, 3].f.writeln;
    [5, 5, 2, 3, 2, 4, 7, 3].f.writeln;
}
Nicolas Chabanovsky
  • 51,426
  • 87
  • 267
  • 507
4

Python3, 120

def f(a,o,i=0,p=[]):s=sum(p);exec(('o+=([p],[])[p in o];'*(s>9)+'f(a,o,i+1,sorted(p+[a[i]]));i+=1;'*(len(a)-i))*(s<11))


Примечание

  • Результат записывается в параметр функции, т.е. вызываем функцию в виде f(input_list_of_numbers, output_list_of_combinations)


Тест на Ideone


Расшифровка кода

def f(a, o, i=0, p=[]):
    s = sum(p);
    if s < 11:
        if s > 9:
            if p not in o:
                o += [p]
        while i < len(a):
            f(a, o, i + 1, sorted(p + [a[i]]))
            i += 1
0

Scala

(1 to 10).map(i => List.fill(i)((1 to 10).toList).flatten.combinations(i).count(_.sum == 10)).sum

Решение, учитывающее варианты типа [ 1+ 1+ 1+ 1+ 2 +2 +2]

В условии говорится "Уже выбранные числа могут использоваться неоднократно" но, например, выйгравший вариант на скале не выводит вариант [ 1+ 1+ 1+ 1+ 2 +2 +2] и ему подобные