Siklus Terpanjang dalam Grafik

18

Diberikan grafik terarah, menghasilkan siklus terpanjang.

Aturan

  • Format input yang masuk akal diizinkan (misalnya daftar tepi, matriks konektivitas).
  • Label tidak penting, jadi Anda dapat memberlakukan batasan pada label yang Anda butuhkan dan / atau inginkan, asalkan label tersebut tidak mengandung informasi tambahan yang tidak diberikan dalam input (mis. Anda tidak dapat mengharuskan bahwa node dalam siklus adalah dilabeli dengan bilangan bulat, dan simpul lainnya diberi label dengan string alfabet).
  • Siklus adalah urutan node yang semuanya terhubung, dan tidak ada simpul yang diulang, selain simpul yang merupakan awal dan akhir siklus ( [1, 2, 3, 1]adalah siklus, tetapi [1, 2, 3, 2, 1]tidak).
  • Jika grafik asiklik, siklus terpanjang memiliki panjang 0, dan karenanya akan menghasilkan output kosong (mis. Daftar kosong, tidak ada output sama sekali).
  • Mengulang simpul pertama di akhir daftar node dalam siklus adalah opsional ( [1, 2, 3, 1]dan [1, 2, 3]menunjukkan siklus yang sama).
  • Jika ada beberapa siklus dengan panjang yang sama, salah satu atau semuanya mungkin merupakan output.
  • Builtin diperbolehkan, tetapi jika solusi Anda menggunakannya, Anda disarankan untuk memasukkan solusi alternatif yang tidak menggunakan builtin yang diremehkan (misalnya builtin yang menghasilkan semua siklus). Namun, solusi alternatif tidak akan dihitung sama sekali dengan skor Anda, sehingga sepenuhnya opsional.

Uji Kasus

Dalam kasus uji ini, input diberikan sebagai daftar tepi (di mana elemen pertama adalah simpul sumber dan elemen kedua adalah simpul tujuan), dan outputnya adalah daftar simpul tanpa pengulangan simpul pertama / terakhir.

[(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]
Mego
sumber
Dalam semua contoh Anda, output Anda dimulai dengan simpul dengan indeks terkecil. Apakah ini persyaratan?
Dada
@ Dada Tidak, itu hanya kebetulan dengan kasus uji. Output harus dimulai (dan secara opsional diakhiri) dengan simpul pertama dalam siklus.
Mego
Anda harus memilih format, dengan titik akhir atau tanpa adalah sewenang-wenang dan tidak menambah tantangan.
Magic Gurita Guci
5
@cococuting saya tidak setuju. Node terakhir implisit jika dibiarkan (karena itu sama dengan node pertama). Mengizinkan pilihan untuk mengulangi simpul pertama atau tidak memungkinkan lebih banyak kebebasan dalam bermain golf.
Mego
1
Terkait, agak .
Fatalkan

Jawaban:

4

Mathematica, 80 58 byte

Menyimpan 22 byte kekalahan berkat JungHwan Min

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

adalah karakter penggunaan pribadi tiga byte yang U+F3D5mewakili \[DirectedEdge]. Fungsi murni dengan argumen pertama #diharapkan menjadi daftar tepi terarah. Temukan Allpanjang siklus paling banyak InfinitydiGraph@# , kemudian menggantikan daftar kosong dengan daftar diri loop. Siklus direpresentasikan sebagai daftar tepi dan disortir menurut panjangnya, jadi kami mengambil siklus yang terakhir, lalu dari semua tepinya, kami mengambil argumen pertama sehingga kami mendapatkan daftar simpul dalam format output yang ditentukan.

Jika hanya Mathematica memperlakukan loop sebagai siklus panjang 1( AcyclicGraphQ @ CycleGraph[1, DirectedEdges -> True]memberi True, serius), maka kita bisa menyimpan 26byte lain :

FindCycle[#,∞,All][[-1,;;,1]]&
ngenisis
sumber
1
Anda tidak perlu MaximalBykarena hasilnya FindCyclesudah diurutkan berdasarkan panjang (elemen terakhir adalah yang terpanjang). Juga, argumen pertama FindCycledapat berupa daftar \[DirectedEdge](bukan a Graph). Plus, Anda dapat menggunakan 2-byte ;;(= 1;;-1) bukan 3-byte Alldalam Partuntuk menyimpan byte. -22 bytes (58 bytes):(FindCycle[#,∞,All]/.{}->{Cases[#,v_v_]})[[-1,;;,1]]&
JungHwan Min
3

Haskell , 157 154 150 byte

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

Cobalah online!

Terima kasih @Laikoni dan @Zgrab karena telah menyelamatkan banyak byte!

Ini adalah program yang sangat tidak efisien:

Fungsi pertama #mengambil daftar jalur l(daftar daftar angka) dan mencoba memperluas elemen ldengan menambahkan setiap tepi yang mungkin (daftar panjang 2) guntuk setiap elemen l. Ini terjadi hanya jika elemen lbelum merupakan siklus dan jika node baru yang akan ditambahkan tidak sudah terkandung dalam elemen l. Jika sudah menjadi siklus, kami tidak menambahkan apa pun selain menambahkannya ke daftar jalur baru, jika kami dapat memperluasnya, kami menambahkan jalur yang diperluas ke daftar baru, jika tidak, kami tidak menambahkannya ke daftar baru .

Sekarang fungsi hberulang kali mencoba untuk memperpanjang jalur tersebut (dimulai dengan daftar tepi itu sendiri) sampai kita mencapai titik tetap, yaitu kita tidak dapat memperluas jalur apa pun lebih jauh. Pada titik ini kami hanya memiliki siklus dalam daftar kami. Maka itu hanya masalah memilih siklus terpanjang. Jelas sekali siklus muncul beberapa kali dalam daftar ini karena setiap kemungkinan rotasi siklus dari siklus adalah siklus.

cacat
sumber
Anda dapat memasukkan tanda kurung (p:q)<-l.
Laikoni
Dan menggunakan <$>bukannya mapharus menyimpan byte lain di ((,)=<<length)<$>[]:.
Laikoni
@Laikoni Terima kasih banyak!
flawr
Anda memiliki ruang ekstra setelah garis akhir. Juga, melakukan d@(p:q)<-lmenghemat beberapa byte.
Zgarb
Oh, d@(p:q)ini benar-benar bagus, terima kasih telah menunjukkan padaku!
flawr
2

Pyth, 20 byte

eMefqhMT.>{eMT1s.pMy

Suite uji

Mengambil daftar tepi, seperti pada contoh.

Penjelasan:

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.
isaacg
sumber
2

Bash + bsdutils, 129 byte

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 melakukan semua pengangkatan berat, tetapi format outputnya agak unik dan tidak mendeteksi siklus panjang 1. Perhatikan bahwa ini tidak bekerja dengan GNU tsort.

Verifikasi

--- 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
Dennis
sumber
2

JavaScript (ES6), 173 163 156 145 139 byte

Disimpan 5 byte berkat @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

Cuplikan tes

Produksi ETH
sumber
Tentunya beralih ke tua biasa mapmenghemat beberapa byte?
Neil
@Neil Pasti .filter().map(), jadi hampir pasti tidak. Switch menyelamatkan saya 10 byte (meskipun tidak sepenuhnya golf seperti sekarang)
ETHproduksi
Saya tidak melihat Anda menggunakan hasil dari pemahaman, jadi alih-alih menggunakan a.filter(z=>!e).map(z=>d)Anda dapat menggunakan a.map(z=>e?0:d).
Neil
Anda benar, saya bisa menggabungkan semuanya untuk menghemat 5 byte. Dan saya baru sadar saya juga tidak perlu a+a?:-)
ETHproduk
Bisakah sang downvoter menjelaskan apa yang salah? Apakah ini menghasilkan output yang salah?
ETHproduk
2

Haskell , 109 108 byte

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])]

Solusi brute force: buat semua daftar tepi dengan panjang yang meningkat hingga panjang input, pertahankan yang merupakan siklus, kembalikan yang terakhir. Mengambil grafik dalam format [(1,2),(2,3),(2,4),(4,1)]. Cobalah online!

Penjelasan

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.
Zgarb
sumber
Sekarang perlu beberapa saat sampai saya akhirnya mengerti apa yang sedang terjadi, bagian untuk memeriksa jalur / siklus benar-benar pintar, saya kagum!
flawr
@ flawr, terima kasih! Nah, tampaknya isaacg pada dasarnya menggunakan algoritma yang sama sebelum saya.
Zgarb
0

MATLAB, 291 byte

Mengambil matriks adjecency di Amana tepi (i,j)dilambangkan dengan 1in A(i,j), dan Anol di semua entri lainnya. Outputnya adalah daftar siklus terpanjang. Daftar ini kosong jika tidak ada siklus sama sekali, dan daftar termasuk awal dan titik akhir jika ada siklus. Itu menggunakan1 pengindeksan berbasis.

Solusi ini tidak menggunakan fungsi bawaan yang terkait dengan grafik.

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

Sayangnya ini tidak berjalan di TryItOnline karena menggunakan fungsi dalam suatu fungsi, yang bersifat rekursif. Sedikit modifikasi memungkinkan Anda untuk mencobanya di octave-online.net .

Untuk kasus tes terakhir saya menemukan alternatif siklus terpanjang [0 2 1 4 3 5 7 8 9 11 10 6 0] (notasi ini menggunakan pengindeksan berbasis 0)

Penjelasan

Pendekatan dasar di sini adalah bahwa kami melakukan BFS dari setiap node dan berhati-hati agar kami tidak mengunjungi salah satu dari intermediate node lagi kecuali node start. Dengan gagasan itu kami dapat mengumpulkan semua siklus yang mungkin, dan dengan mudah memilih yang terpanjang.

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
cacat
sumber