그래프에서 가장 긴주기


18

유 방향 그래프가 주어지면 가장 긴주기를 출력하십시오.

규칙

  • 합리적인 입력 형식이 허용됩니다 (예 : 모서리 목록, 연결 매트릭스).
  • 레이블은 중요하지 않으므로 입력에 제공되지 않은 추가 정보를 포함하지 않는 한 필요하거나 원하는 레이블에 제한을 둘 수 있습니다 (예 :주기의 노드를 요구할 수는 없습니다) 정수로 레이블이 지정되고 다른 노드는 알파벳 문자열로 레이블이 지정됩니다).
  • 주기는 모든 노드가 연결되어 있으며주기의 시작과 끝인 노드 ( [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]

모든 예제에서 출력은 가장 작은 인덱스를 가진 노드로 시작합니다. 이것이 필수 요건입니까?
Dada

@Dada 아니요, 테스트 사례와 일치합니다. 사이클의 첫 번째 노드에서 출력이 시작되고 선택적으로 종료되어야합니다.
Mego

엔드 포인트가 있거나없는 형식은 임의적이어야하며 문제에 아무 것도 추가하지 않습니다.
Magic Octopus Urn

5
@carusocomputing 동의하지 않습니다. 마지막 노드는 첫 번째 노드와 동일하므로 중단 된 경우 내재적입니다. 첫 번째 노드의 반복 여부를 선택하면 골프를 더 자유롭게 할 수 있습니다.
Mego

1
관련이 있습니다.
Fatalize

답변:


4

Mathematica, 80 58 바이트

정환 민 덕분에 무려 22 바이트 절약

(FindCycle[#,∞,All]/.{}->{Cases[#,v_v_]})[[-1,;;,1]]&

세 바이트 점용 문자 U+F3D5표현은 \[DirectedEdge]. 첫 번째 인수가 포함 된 순수한 함수는 #지정된 모서리의 목록이 될 것으로 예상됩니다. 발견의 All최대 길이의주기 Infinity에서는 Graph@#다음 자기 루프의 목록이 빈 목록을 대체합니다. 주기는 모서리리스트로 표시되고 길이별로 정렬되므로 마지막주기를 취한 다음 모든 모서리에서 첫 번째 인수를 취하여 지정된 출력 형식으로 정점리스트를 얻습니다.

Mathematica 만 루프를 길이의주기 1( 심각하게 AcyclicGraphQ @ CycleGraph[1, DirectedEdges -> True]제공) 로 처리 True하면 다른 26바이트를 절약 할 수 있습니다 .

FindCycle[#,∞,All][[-1,;;,1]]&

1
MaximalBy결과 FindCycle는 이미 길이별로 정렬되어 있기 때문에 필요하지 않습니다 (마지막 요소가 가장 깁니다). 또한의 첫 번째 인수 FindCycle\[DirectedEdge](대신)의 목록 일 수 있습니다 Graph. 게다가, 당신은 2 바이트 사용할 수 있습니다 ;;(= 1;;-1대신 3 바이트)를 All에서 Part바이트 저장합니다. -22 바이트 (58 바이트) :(FindCycle[#,∞,All]/.{}->{Cases[#,v_v_]})[[-1,;;,1]]&
JungHwan Min

3

하스켈 , 157154150 바이트

import Data.List
g#l=nub[last$(e:d):[d|p==last q||e`elem`init d]|d@(p:q)<-l,[e,f]<-g,p==f]
h g=snd$maximum$((,)=<<length)<$>[]:until((==)=<<(g#))(g#)g

온라인으로 사용해보십시오!

많은 바이트를 저장해 준 @Laikoni와 @Zgrab에게 감사합니다!

이것은 매우 비효율적 인 프로그램입니다.

첫 번째 함수 #는 경로 l목록 (숫자 목록)을 가져 와서 l가능한 모든 모서리 (길이 2 목록) g를의 각 요소 앞에 추가 하여 요소를 확장하려고합니다 l. 이것은의 요소가있는 경우에만 발생 l이미 사이클 아니다 앞에 추가 될 새 노드가 이미의 요소에 포함되지 않은 경우 l. 이미 사이클 인 경우에는 아무것도 추가하지 않고 새 경로 목록에 다시 추가합니다. 확장 할 수 있으면 확장 된 경로를 새 목록에 추가하고 그렇지 않으면 새 목록에 추가하지 않습니다 .

이제 함수 h는 고정 점에 도달 할 때까지 (가장자리 목록 자체부터 시작하여) 해당 경로를 반복적으로 확장하려고 시도합니다. 즉, 더 이상 경로를 확장 할 수 없습니다. 이 시점에서 우리는 목록에 사이클 만 있습니다. 그렇다면 가장 긴 사이클을 선택하는 것입니다. 사이클의 가능한 모든 순환 회전이 다시 사이클이기 때문에 사이클이이 목록에 여러 번 나타납니다.


에 괄호를 놓을 수 있습니다 (p:q)<-l.
Laikoni

<$>대신에를 사용하여에 map다른 바이트를 저장해야합니다 ((,)=<<length)<$>[]:.
Laikoni

@Laikoni 대단히 감사합니다!
flawr

마지막 줄 뒤에 여분의 공간이 있습니다. 또한 이렇게 d@(p:q)<-l하면 일부 바이트 가 절약됩니다.
Zgarb

오, d@(p:q)정말 멋져 보여줘서 고마워!
flawr

2

Pyth, 20 바이트

eMefqhMT.>{eMT1s.pMy

테스트 스위트

예제와 같이 가장자리 목록을 가져옵니다.

설명:

eMefqhMT.>{eMT1s.pMy
eMefqhMT.>{eMT1s.pMyQ    Variable introduction
                   yQ    Take all subsets of the input, ordered by length
                .pM      Reorder the subsets in all possible ways
               s         Flatten
                         (This should be a built in, I'm going to make it one.)
   f                     Filter on (This tests that we've found a cycle)
    qhMT                 The list of first elements of edges equals
           eMT           The last elements
         .>   1          Rotated right by 1
        {                Deduplicated (ensures no repeats, which would not be a
                         simple cycle)
  e                      Take the last element, which will be the longest one.
eM                       Take the last element of each edge, output.

2

Bash + bsdutils, 129 바이트

sed 's/^\(.*\) \1$/x \1 \1 x/'|sort|(tsort -l>&-)|&tr c\\n '
 '|sed 's/x //g'|awk 'm<NF{m=NF;gsub(/[^0-9 ] ?/,"");print}'|tail -1

tsort 는 모든 무거운 작업을 수행하지만 출력 형식은 다소 독특하며 길이 1의주기를 감지하지 못합니다. 이것은 GNU tsort에서는 작동하지 않습니다.

확인

--- t1 ---
0
--- t2 ---
--- t3 ---
0 1
--- t4 ---
1 2 4 5
--- t5 ---
0 2 4 6 8
--- t6 ---
0 2 1 6 3 7 4 8 9 5
--- t7 ---
0 11 10 3 1 2 4 7 5 8 9 6

2

자바 스크립트 (ES6) 173 163 156 145 139 바이트

@Neil 덕분에 5 바이트 절약

f=(a,m,b=[])=>a.map(z=>!([x,y]=z,m&&x-m.slice(-1))&&b.length in(c=(n=m||[x],q=n.indexOf(y))?~q?b:f(a.filter(q=>q!=z),[...n,y]):n)?b=c:0)&&b

테스트 스 니펫


확실히 오래된 것으로 바꾸면 map몇 바이트가 절약됩니까?
Neil

@Neil이어야 할 .filter().map()것이므로 거의 확실하지 않습니다. 이 스위치는 10 바이트를 절약했습니다 (현재와 같이 완전히 골프화되지는 않았지만)
ETHproductions

이해의 결과를 사용하는 것을 보지 못하여 사용하는 대신을 사용할 a.filter(z=>!e).map(z=>d)수 있습니다 a.map(z=>e?0:d).
Neil

맞습니다. 모든 것을 결합하여 5 바이트를 절약 할 수 있습니다. 그리고 난 그냥 필요가 없습니다 실현 a+a?:-) 중
ETHproductions

downvoter가 무엇이 잘못되었는지 설명해 주시겠습니까? 잘못된 출력을 생성합니까?
ETHproductions

2

하스켈 , 109 108 바이트

import Data.List
f g=last$[]:[b|n<-[1..length g],e:c<-mapM(\_->g)[1..n],b<-[snd<$>e:c],b==nub(fst<$>c++[e])]

무차별 대입 솔루션 : 입력 길이까지 길이가 증가하는 모든 모서리 목록을 생성하고, 순환 길이를 유지하고, 마지막 모서리를 반환합니다. 형식으로 그래프를 가져옵니다 [(1,2),(2,3),(2,4),(4,1)]. 온라인으로 사용해보십시오!

설명

f g=                    -- Define function f on input g as
  last$                 -- the last element of the following list
  []:                   -- (or [], if the list is empty):
  [b|                   --  lists of vertices b where
   n<-[1..length g],    --  n is between 1 and length of input,
   e:c<-                --  list of edges with head e and tail c is drawn from
    mapM(\_->g)[1..n],  --  all possible ways of choosing n edges from g,
   b<-[snd<$>e:c],      --  b is the list of second elements in e:c,
   b==                  --  and b equals
    nub(fst<$>c++[e])]  --  the de-duplicated list of first elements
                        --  in the cyclic shift of e:c.

마침내 무슨 일이 일어나고 있는지 이해할 때까지 시간이 걸렸습니다. 경로 /주기를 확인하는 부분은 정말 영리합니다.
flawr

@flawr 감사합니다! 글쎄, isaacg 는 본질적으로 같은 알고리즘을 사용 했습니다 .
Zgarb

0

MATLAB, 291260 바이트

adjecency 행렬 얻어 A에지가 (i,j)a로 나타낸다 1하여 A(i,j), 그리고 A다른 모든 항목에서 제로이다. 출력은 가장 긴주기의 목록입니다. 사이클이 전혀 없으면 목록이 비어 있고 사이클이 있으면 목록에 시작 및 끝 점이 포함됩니다. 1기반 인덱싱을 사용 합니다.

이 솔루션은 그래프와 관련된 내장 함수를 사용하지 않습니다.

function c=f(A);N=size(A,1);E=eye(N);c=[];for j=1:N;l=g(j);if numel(l)>numel(c);c=l;end;end;function p=g(p)if ~any(find(p(2:end)==p(1)))e=E(p(end),:)Q=find(e*A)k=[];for q=Q;if ~ismember(q,p(2:end))n=g([p,q]);if numel(n)>numel(k);k=n;end;end;end;p=k;end;end;end

불행히도 이것은 함수 내에서 함수를 사용하기 때문에 TryItOnline에서 실행되지 않습니다. 약간의 수정으로 octave-online.net 에서 시도해 볼 수 있습니다 .

가장 마지막 테스트 사례에서 대안으로 가장 긴주기를 찾았습니다 [0 2 1 4 3 5 7 8 9 11 10 6 0](이 표기법은 0 기반 색인 사용).

설명

여기서 기본적인 접근 방식은 모든 노드에서 BFS를 수행하고 시작 노드를 제외하고는 중간 노드를 다시 방문하지 않도록주의하는 것입니다. 이를 통해 가능한 모든주기를 수집하고 가장 긴주기를 쉽게 선택할 수 있습니다.

function c=f(A);
N=size(A,1);
E=eye(N);
c=[]; % current longest cycle
for j=1:N;                                      % iterate over all nodes
    l=getLongestCycle(j);                       % search the longest cycle through the current node
    if numel(l)>numel(c);                       % if we find a longer cycle, update our current longest cycle
        c=l;
    end;

end;

    function p=getLongestCycle(p);              % get longest cycle from p(1) using recursion
        if ~any(find(p(2:end)==p(1)));          % if we just found a cycle, return the cycle do nothing else, OTHERWISE:
            e=E(p(end),:);                      % from the last node, compute all outgoing edges
            Q=find(e*A);                        
            k=[];                               
            for q=Q;                            % iterate over all outogoin edges
                if ~ismember(q,p(2:end));       % if we haven't already visited this edge,
                    n=getLongestCycle([p,q]);   % recursively search from the end node of this edge
                    if numel(n)>numel(k);       % if this results in a longer cycle, update our current longest cycle
                        k=n;
                    end;
                end;
            end;
            p=k;
        end;
    end; 
end
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.