Учитывая ориентированный граф, выведите самый длинный цикл.
правила
- Разрешен любой разумный формат ввода (например, список ребер, матрица связности).
- Метки не важны, поэтому вы можете наложить любые ограничения на метки, которые вам нужны и / или желательны, если они не содержат дополнительную информацию, не указанную во входных данных (например, вы не можете требовать, чтобы узлы в циклах были помечены целыми числами, а другие узлы помечены буквенными строками).
- Цикл - это последовательность узлов, которые все связаны, и ни один узел не повторяется, кроме узла, который является началом и концом цикла (
[1, 2, 3, 1]
это цикл, но[1, 2, 3, 2, 1]
это не так). - Если график является ациклическим, самый длинный цикл имеет длину 0 и, следовательно, должен давать пустой вывод (например, пустой список, вообще не выводить).
- Повторять первый узел в конце списка узлов в цикле необязательно (
[1, 2, 3, 1]
и[1, 2, 3]
обозначать тот же цикл). - Если есть несколько циклов одинаковой длины, любой или все из них могут быть выведены.
- Встроенные функции разрешены, но если ваше решение использует их, рекомендуется включить альтернативное решение, которое не использует тривиализируемые встроенные функции (например, встроенное, которое выводит все циклы). Тем не менее, альтернативное решение не будет учитываться при подсчете очков, поэтому оно не является обязательным.
Тестовые случаи
В этих тестовых случаях входные данные задаются в виде списка ребер (где первый элемент является узлом источника, а второй элемент является узлом назначения), а выходные данные представляют собой список узлов без повторения первого / последнего узла.
[(0, 0), (0, 1)] -> [0]
[(0, 1), (1, 2)] -> []
[(0, 1), (1, 0)] -> [0, 1]
[(0, 1), (1, 2), (1, 3), (2, 4), (4, 5), (5, 1)] -> [1, 2, 4, 5]
[(0, 1), (0, 2), (1, 3), (2, 4), (3, 0), (4, 6), (6, 8), (8, 0)] -> [0, 2, 4, 6, 8]
[(0, 0), (0, 8), (0, 2), (0, 3), (0, 9), (1, 0), (1, 1), (1, 6), (1, 7), (1, 8), (1, 9), (2, 1), (2, 3), (2, 4), (2, 5), (3, 8), (3, 1), (3, 6), (3, 7), (4, 1), (4, 3), (4, 4), (4, 5), (4, 6), (4, 8), (5, 0), (5, 8), (5, 4), (6, 0), (6, 1), (6, 2), (6, 3), (6, 4), (6, 5), (6, 6), (6, 7), (6, 9), (7, 0), (7, 1), (7, 2), (7, 3), (7, 4), (7, 5), (7, 8), (7, 9), (8, 0), (8, 1), (8, 2), (8, 5), (8, 9), (9, 1), (9, 2), (9, 3), (9, 4), (9, 5), (9, 6)] -> [0, 9, 6, 7, 8, 2, 5, 4, 3, 1]
[(0, 0), (0, 2), (0, 4), (0, 5), (0, 7), (0, 9), (0, 11), (1, 2), (1, 4), (1, 5), (1, 8), (1, 9), (1, 10), (2, 0), (2, 1), (2, 3), (2, 4), (2, 5), (2, 6), (3, 0), (3, 1), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (3, 11), (4, 1), (4, 3), (4, 7), (4, 8), (4, 9), (4, 10), (4, 11), (5, 0), (5, 4), (5, 6), (5, 7), (5, 8), (5, 11), (6, 0), (6, 8), (6, 10), (6, 3), (6, 9), (7, 8), (7, 9), (7, 2), (7, 4), (7, 5), (8, 8), (8, 9), (8, 2), (8, 4), (8, 7), (9, 0), (9, 1), (9, 2), (9, 3), (9, 6), (9, 10), (9, 11), (10, 8), (10, 3), (10, 5), (10, 6), (11, 2), (11, 4), (11, 5), (11, 9), (11, 10), (11, 11)] -> [0, 11, 10, 6, 9, 3, 8, 7, 5, 4, 1, 2]
Ответы:
Mathematica,
8058 байтСпасло колоссальные 22 байта благодаря JungHwan Min
это три байта частного использование символов ,U+F3D5
представляющие\[DirectedEdge]
. Чистая функция с первым аргументом#
должна быть списком направленных ребер. НаходитAll
циклы длины максимумInfinity
вGraph@#
, затем заменяют пустой список со списком самооценок петель. Циклы представлены в виде списков ребер и отсортированы по длине, поэтому мы берем последний такой цикл, затем из всех его ребер мы берем первый аргумент, чтобы получить список вершин в указанном выходном формате.Если только Mathematica рассматривает циклы как цикл длины
1
(AcyclicGraphQ @ CycleGraph[1, DirectedEdges -> True]
даетTrue
, серьезно), то мы могли бы сохранить другие26
байты:источник
MaximalBy
потому что результатFindCycle
уже отсортирован по длине (последний элемент самый длинный). Кроме того, первый аргументFindCycle
может быть списком\[DirectedEdge]
(вместоGraph
). Кроме того , вы можете использовать 2-байты;;
(=1;;-1
) вместо 3- х байтAll
в ,Part
чтобы сохранить байты. -22 байта (58 байтов):(FindCycle[#,∞,All]/.{}->{Cases[#,v_v_]})[[-1,;;,1]]&
Haskell ,
157 154150 байтПопробуйте онлайн!
Спасибо @Laikoni и @Zgrab за сохранение нескольких байтов!
Это очень неэффективная программа:
Первая функция
#
берет список путейl
(список списков чисел) и пытается расширить элементыl
, добавляя каждое возможное ребро (список длиной 2)g
каждого элементаl
. Это происходит только в том случае, если элементl
не является циклом и если новый добавляемый узел еще не содержится в элементеl
. Если это уже цикл, мы ничего не добавляем, а добавляем его снова в новый список путей, если мы можем его расширить, мы добавляем расширенный путь в новый список, в противном случае мы не добавляем его в новый список. ,Теперь функция
h
многократно пытается расширить эти пути (начиная со самого списка ребер), пока мы не достигнем фиксированной точки, то есть мы не можем расширять любой путь дальше. На данный момент у нас есть только циклы в нашем списке. Тогда это просто вопрос выбора самого длинного цикла. Очевидно, что циклы появляются в этом списке несколько раз, поскольку каждое возможное циклическое вращение цикла снова является циклом.источник
(p:q)<-l
.<$>
вместоmap
должно сохранить другой байт в((,)=<<length)<$>[]:
.d@(p:q)<-l
экономит несколько байтов.d@(p:q)
это действительно мило, спасибо, что показали мне!Pyth, 20 байт
Тестирование
Принимает список ребер, как в примерах.
Объяснение:
источник
Bash + bsdutils, 129 байт
tsort выполняет всю тяжелую работу, но его выходной формат довольно уникален, и он не определяет циклы длины 1. Обратите внимание, что это не работает с GNU tsort.
верификация
источник
JavaScript (ES6),
173163156145139 байтСохранено 5 байт благодаря @Neil
Тестовый фрагмент
Показать фрагмент кода
источник
map
экономит вам пару байтов?.filter().map()
, так что почти наверняка нет. Переключатель сэкономил мне 10 байт (хотя он не был таким же удачным, как сейчас)a.filter(z=>!e).map(z=>d)
вы можете использоватьa.map(z=>e?0:d)
.a+a?
:-)Haskell ,
109108 байтРешение для грубой силы: генерируйте все списки ребер с увеличивающейся длиной до длины ввода, сохраняйте циклы и возвращайте последний. Берет график в формате
[(1,2),(2,3),(2,4),(4,1)]
. Попробуйте онлайн!объяснение
источник
MATLAB,
291260 байтПринимает матрицу приличия, в
A
которой ребро(i,j)
обозначено как1
inA(i,j)
, иA
равно нулю во всех других записях. Вывод представляет собой список самого длинного цикла. Список пуст, если цикла вообще нет, и список содержит начальную и конечную точки, если цикл существует. Он использует1
индексацию на основе.Это решение не использует никаких встроенных функций, связанных с графиками.
К сожалению, это не выполняется в TryItOnline, поскольку использует функцию внутри функции, которая является рекурсивной. Небольшая модификация позволяет вам попробовать это на octave-online.net .
Для самого последнего контрольного примера я нашел альтернативный самый длинный цикл
[0 2 1 4 3 5 7 8 9 11 10 6 0]
(в этой записи используется индексирование на основе 0)объяснение
Основной подход здесь заключается в том, что мы выполняем BFS с каждого узла и заботимся о том, чтобы мы больше не посещали ни один из промежуточных узлов, кроме начального узла. С этой идеей мы можем собрать все возможные циклы и легко выбрать самый длинный.
источник