วงจรที่ยาวที่สุดในกราฟ


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

@ ดาดาไม่นั่นเป็นเพียงเรื่องบังเอิญกับกรณีทดสอบ เอาต์พุตควรเริ่มต้น (และสิ้นสุดแบบเป็นทางเลือก) กับโหนดแรกในรอบ
Mego

คุณควรเลือกรูปแบบโดยมีจุดปลายหรือไม่มีรูปแบบใดก็ได้และไม่เพิ่มสิ่งที่ท้าทาย
Magic Octopus Urn

5
@carusocomputing ฉันไม่เห็นด้วย โหนดสุดท้ายนั้นโดยปริยายหากปล่อยทิ้งไว้ (เนื่องจากมันเหมือนกันกับโหนดแรก) การอนุญาตให้เลือกว่าจะทำซ้ำโหนดแรกหรือไม่จะช่วยให้มีอิสระในการเล่นกอล์ฟมากขึ้น
Mego

1
ที่เกี่ยวข้องครับ
ทำให้เสียชีวิต

คำตอบ:


4

Mathematica, 80 58 ไบต์

บันทึก 22 ไบต์ขอบคุณมากกับ JungHwan Min

(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 bytes (58 bytes):(FindCycle[#,∞,All]/.{}->{Cases[#,v_v_]})[[-1,;;,1]]&
JungHwan Min Min

3

Haskell , 157 154 150 ไบต์

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โดย prepending ทุกขอบที่เป็นไปได้ (รายการที่มีความยาว 2) ขององค์ประกอบของแต่ละg lสิ่งนี้จะเกิดขึ้นเฉพาะในกรณีที่องค์ประกอบของlไม่ได้เป็นวัฏจักรอยู่แล้วและหากโหนดใหม่ที่จะได้รับการเติมเต็มนั้นไม่มีอยู่ในองค์ประกอบของlถ้าโหนดใหม่ที่จะใช้ได้ไม่ได้มีอยู่แล้วในองค์ประกอบของถ้ามันเป็นวัฏจักรอยู่แล้วเราไม่ได้ทำอะไรเลย แต่เพิ่มมันอีกครั้งในรายการเส้นทางใหม่ถ้าเราสามารถขยายมันได้เราเพิ่มเส้นทางที่ขยายไปยังรายการใหม่มิฉะนั้นเราจะไม่เพิ่มมันเข้าไปในรายการใหม่ .

ตอนนี้ฟังก์ชั่นhพยายามที่จะขยายเส้นทางเหล่านั้นซ้ำ ๆ (เริ่มต้นด้วยรายการของขอบตัวเอง) จนกว่าเราจะถึงจุดคงที่นั่นคือเราไม่สามารถขยายเส้นทางใด ๆ เพิ่มเติม ณ จุดนี้เรามีวงจรในรายการของเราเท่านั้น จากนั้นมันเป็นเพียงเรื่องของการเลือกรอบที่ยาวที่สุด เห็นได้ชัดว่ารอบปรากฏขึ้นหลายครั้งในรายการนี้เนื่องจากทุกรอบการหมุนที่เป็นไปได้ของรอบเป็นรอบอีกครั้ง


(p:q)<-lคุณสามารถวางวงเล็บใน
Laikoni

และใช้<$>แทนควรบันทึกไบต์อีกmap ((,)=<<length)<$>[]:
Laikoni

@Laikoni ขอบคุณมาก!
ข้อบกพร่อง

คุณมีพื้นที่เพิ่มเติมหลังจากบรรทัดสุดท้าย นอกจากนี้การทำd@(p:q)<-lบันทึกบางไบต์
Zgarb

โอ้d@(p:q)เป็นสิ่งที่ดีจริงๆขอบคุณที่แสดงให้ฉัน!
ข้อบกพร่อง

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

JavaScript (ES6), 173 163 156 145 139 ไบต์

บันทึก 5 ไบต์ด้วย @Neil

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

Haskell , 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 ขอบคุณ! ดูเหมือนว่าisaacg จะใช้อัลกอริทึมเดียวกันก่อนหน้าฉัน
Zgarb

0

MATLAB, 291 260 ไบต์

ใช้เวลาเมทริกซ์ adjecency Aที่ขอบ(i,j)จะเขียนแทนโดย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 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.