Węzłowa sytuacja

35

Biorąc pod uwagę oznaczenie węzła i znaki przecięcia przez Dowkera, oblicz jego wielomian nawiasu.

Chociaż istnieją bardziej techniczne definicje, do tego wyzwania wystarczy pomyśleć o węźle jako o czymś fizycznie wykonanym przez połączenie dwóch końców sznurka razem. Ponieważ sęki istnieją w trzech wymiarach, kiedy rysujemy je na papierze, używamy diagramów węzłów - dwuwymiarowych rzutów, w których skrzyżowania mają dokładnie dwie linie, jeden nad i jeden pod spodem.

wprowadź opis zdjęcia tutaj

Tutaj (b) i (c) są różnymi schematami tego samego węzła.

Jak przedstawiamy schemat węzłów na papierze? Większość z nas nie jest Rembrandtem, więc polegamy na notacji Dowkera , która działa w następujący sposób:

Wybierz dowolny punkt początkowy węzła. Poruszaj się w dowolnym kierunku wzdłuż węzła i numeruj napotkane skrzyżowania, zaczynając od 1, z następującą modyfikacją: jeśli jest to liczba parzysta i aktualnie przechodzisz przez skrzyżowanie, zaneguj tę liczbę parzystą. Na koniec wybierz liczby parzyste odpowiadające 1, 3, 5 itd.

Spróbujmy przykładu:

wprowadź opis zdjęcia tutaj

W tym węźle wybraliśmy „1” jako punkt wyjścia i ruszyliśmy w górę i w prawo. Za każdym razem, gdy przechodzimy nad lub pod innym kawałkiem liny, wyznaczamy punkt przecięcia kolejnej liczby naturalnej. Negujemy liczby parzyste odpowiadające pasmom przechodzącym przez skrzyżowanie, na przykład [3,-12]na schemacie. Tak więc ten diagram byłby reprezentowany przez [[1,6],[2,5],[3,-12],[-4,9],[7,8],[-10,11]]. Lista znajomych 1, 3, 5, 7 itd. Daje nam [6,-12,2,8,-4,-10].

Należy tutaj zwrócić uwagę na kilka rzeczy. Po pierwsze, notacja Dowkera nie jest unikalna dla danego węzła, ponieważ możemy wybrać dowolny punkt początkowy i kierunek. Ale biorąc pod uwagę zapis, można w pełni określić strukturę węzła (technicznie, aż do odzwierciedlenia jego głównych składników węzła). Chociaż nie wszystkie notacje Dowkera mogą tworzyć możliwe węzły, w tym problemie można założyć, że dane wejściowe reprezentują rzeczywisty węzeł.

Aby uniknąć niejednoznaczności między odbiciami węzła i ułatwić zadanie do rozwiązania, otrzymasz również listę znaków przejścia .

wprowadź opis zdjęcia tutaj

W dodatnim przejściu dolna linia idzie w lewo z punktu widzenia górnej linii. Na skrzyżowaniu ujemnym idzie w prawo. Zauważ, że odwrócenie kierunku owijania się wokół węzła (tj. Odwrócenie zarówno linii ponad i pod linią) nie zmienia znaków przecięcia. W naszym przykładzie są to znaki skrzyżowania [-1,-1,-1,1,-1,1]. Są one podane w tej samej kolejności co notacja Dowkera, tzn. Dla skrzyżowań o numerach 1, 3, 5, 7 itd.

A

DD

wprowadź opis zdjęcia tutaj

  1. Jedyna pętla bez żadnych skrzyżowań ma wielomian 1.

  2. DDD(A2A2)

  3. Dwprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

Na powyższym obrazie zarysowane skrzyżowanie na pierwszym schemacie, które jest w formie wprowadź opis zdjęcia tutaj, można przekształcić wprowadź opis zdjęcia tutajtak, jak na drugiej figurze (inaczej wygładzanie dodatnie ) lub wprowadź opis zdjęcia tutajna trzeciej figurze ( wygładzanie ujemne ).

AA1

wprowadź opis zdjęcia tutaj

Zdezorientowany? Zróbmy przykład, próbując znaleźć nawias klamrowy wprowadź opis zdjęcia tutaj(Uwaga: są to dwa węzły połączone razem. Ten rodzaj diagramu nie będzie potencjalnym wkładem w to wyzwanie, ponieważ wejściowe będą tylko pojedyncze węzły, ale mogą wyglądać jak wynik pośredni w algorytmie).

Najpierw używamy zasady 3

wprowadź opis zdjęcia tutaj

Używamy ponownie reguły 3 w obu nowych węzłach

wprowadź opis zdjęcia tutaj

Zastępujemy te 4 nowe węzły pierwszym równaniem.

wprowadź opis zdjęcia tutaj

Zastosowanie zasad 1 i 2 do tych 4 mówi nam

wprowadź opis zdjęcia tutaj

To nam powiedz

wprowadź opis zdjęcia tutaj

Gratulujemy ukończenia krótkiego wstępu do teorii węzłów!

Wkład

Dwie listy:

  • Notacja Dowker, np [6,-12,2,8,-4,-10]. Numeracja skrzyżowań musi zaczynać się od 1. Odpowiednie liczby nieparzyste [1,3,5,7,...]są niejawne i nie mogą być podawane jako dane wejściowe.

  • Znaki ( 1/ -1lub jeśli wolisz 0/ 1lub false/ truelub '+'/ '-') dla skrzyżowań odpowiadających notacji Dowker, np [-1,-1,-1,1,-1,1].

Zamiast pary list możesz mieć listę par, np [[6,-1],[-12,-1],...

Wydajność

A2+5+AA3[[1,-2],[5,0],[1,1],[-1,3]]

kkkN[0,1,0,5,1,0,-1]A0

Zasady

To wyzwanie dla . Nie można użyć żadnej ze standardowych luk, a biblioteki, które mają narzędzia do obliczania notacji Dowkera lub wielomianów wspornika, nie mogą być używane. (Nadal można używać języka zawierającego te biblioteki, ale nie bibliotek / pakietów).

Testy

// 4-tuples of [dowker_notation, crossing_signs, expected_result, description]
[
 [[],[],[[1,0]],"unknot"],
 [[2],[1],[[-1,3]],"unknot with a half-twist (positive crossing)"],
 [[2],[-1],[[-1,-3]],"unknot with a half-twist (negative crossing)"],
 [[2,4],[1,1],[[1,6]],"unknot with two half-twists (positive crossings)"],
 [[4,6,2],[1,1,1],[[1,-7],[-1,-3],[-1,5]],"right-handed trefoil knot, 3_1"],
 [[4,6,2,8],[-1,1,-1,1],[[1,-8],[-1,-4],[1,0],[-1,4],[1,8]],"figure-eight knot, 4_1"],
 [[6,8,10,2,4],[-1,-1,-1,-1,-1],[[-1,-7],[-1,1],[1,5],[-1,9],[1,13]],"pentafoil knot, 5_1"],
 [[6,8,10,4,2],[-1,-1,-1,-1,-1],[[-1,-11],[1,-7],[-2,-3],[1,1],[-1,5],[1,9]],"three-twist knot, 5_2"],
 [[4,8,10,2,12,6],[1,1,-1,1,-1,-1],[[-1,-12],[2,-8],[-2,-4],[3,0],[-2,4],[2,8],[-1,12]],"6_3"],
 [[4,6,2,10,12,8],[-1,-1,-1,-1,-1,-1],[[1,-10],[2,-2],[-2,2],[1,6],[-2,10],[1,14]],"granny knot (sum of two identical trefoils)"],
 [[4,6,2,-10,-12,-8],[1,1,1,1,1,1],[[1,-14],[-2,-10],[1,-6],[-2,-2],[2,2],[1,10]],"square knot (sum of two mirrored trefoils)"],
 [[6,-12,2,8,-4,-10],[-1,-1,-1,1,-1,1],[[1,-2],[1,6],[-1,10]],"example knot"]
]

Zasoby zewnętrzne

Nie jest konieczne do podjęcia wyzwania, ale jeśli jesteś zainteresowany:


posty w piaskownicy: 1 , 2

dziękuję @ChasBrown i @ H.Pwiz za złapanie błędu w mojej definicji zapisu Dowker

Don Thousand
źródło
Komentarze nie są przeznaczone do rozszerzonej dyskusji; ta rozmowa została przeniesiona do czatu .
Mego
1
@ngn: Znacznie lepiej! Zgadywałem, że o to właśnie chodziło, ale to trochę dziwne wyrażanie języka. :)
Chas Brown

Odpowiedzi:

10

K (ngn / k) , 196 193 bajtów

{!N::2*n:#x;{+/d,'x,'d:&:'-2!(|/n)-n:#:'x}(+/1-2*s){j::+,/y;,/(&0|2*x;(-1+#?{x[j]&:x@|j;x}/!N){-(d,x)+x,d:&4}/,1;&0|-2*x)}'(N!{(x,'|1+x;x+/:!2)}'((2*!n),'-1+x|-x)@'0 1=/:x>0)@'/:+~(y<0)=s:!n#2}

Wypróbuj online!

ngn
źródło
12

Brain-Flak , 1316 bajtów

(({})<({()<(({}<>))><>}){(({})[()()]<{([{}]({})<>({}<>))}{}(([({}<>)]<<>({}<>)<>((({})<<>{({}<>)<>}<>>))>)){({}<>)<>}<>{}(({}<{}(({}<{({}<>)<>}>))>))<>{({}<>)<>}>)}<>>){(({}){}()<({}<>)>)<>{}(({}){}<>)<>}<>{}{}(()){(<({}<({}<>)>)>)<>((){[()](<(({})<>){({}[({})]<>({}<>))}{}({}<>({}<{}<>{({}<>)<>}>)[()])<>({}({})[()])(([()]{()(<({}[({})]())>)}{})<{(<{}{}>)}{}><>{()((<({}()[({}<>)])<>>))}{}<{}{}>)((){[()]<({}()<({}<({}<<>({()<({}<>)<>>}<>){({}[()]<(({})<({()<({}<>)<>>})<>>)<>{({}[()]<<>({}<>)>)}{}>)}<>>)<>>)>)((){[()](<{}(({})<<>(({})<(<<>({}<<>({}<(()()){({}[()]<([{}]()<>)<>({}<<>{({}({})<>[({}<>)])}{}{}>){({}<>)<>}<>>)}{}>{})>)>)<>{}{({}<>)<>}<>([({}<>)]<((()))>)(())<>({}<>)<>{}({}[()]){<>({}<<>(()()){({}[()]<({}<<>{({}<>)<>}>){({}[({})]<>({}<>))}{}(({})<<>({}<>)<>([{}])>)>)}{}{}>)<>({}<(({})())>[()]<>)}{}({}<<>{}([{}]()<{({}<>)<>}>){({}({})<>[({}<>)])}{}{}>){({}<>)<>}<>{}{}{}>{})>)>)}{}){(<{}(({})<<>(({}{})<<>(<({}<>)>)<>{}{({}<>)<>}<>>(({}){}){})>)>)}>}{}){(<{}([{}]<({}<<>([{}]()<>)<>({}<<>{({}({})<>[({}<>)])}{}{}>){({}<>)<>}<>>({})({}){})>)>)}{}>)}{}){{}(([{}]){}<>{}{}<<>({}<>{}){([{}]({}()()<{}({}<>)(())<>>))}{}{}{}>{})(())<>{{}({}<>)(())<>}(<>)<>}{}}{}{}<>{}{}({}<{{}({}<>)(())<>}<>{{}{((<(())>))}{}}{}{{}({}<>)(())<>}>)<>{{}({}<(<()>)<>([]){{}({}<>)(())<>([])}{}>)<>{{}({}<>)<>}{}{}({}<>)<>}<>

Wypróbuj online!

Niczego nie żałuję. Dane wejściowe to spłaszczona lista par.

# Part 1: extract edges
(({})<

({()<(({}<>))><>}){

(({})[()()]<

{([{}]({})<>({}<>))}{}(([({}<>)]<<>({}<>)<>((({})<<>{({}<>)<>}<>>))>)){({}<>)<>}

<>{}(({}<{}(({}<{({}<>)<>}>))>))<>{({}<>)<>}

>)}

<>>){(({}){}()<({}<>)>)<>{}(({}){}<>)<>}<>

{}{}(())

# Part 2: Compute bracket polynomial
{

  # Move degree/sign to other stack
  (<({}<({}<>)>)>)<>

  # If current shape has crossings:
  ((){[()](<

    # Consider first currently listed edge in set
    # Find the other edge leaving same crossing
    (({})<>){({}[({})]<>({}<>))}{}

    # Move to top of other stack
    # Also check for twist
    ({}<>({}<{}<>{({}<>)<>}>)[()])

    # Check for twist in current edge
    <>({}({})[()])

    (

      # Remove current edge if twist
      ([()]{()(<({}[({})]())>)}{})<{(<{}{}>)}{}>

      # Remove matching edge if twist
      <>{()((<({}()[({}<>)])<>>))}{}<{}{}>

    # Push 1 minus number of twists from current vertex.
    )

    # If number of twists is not 1:
    ((){[()]<

      # While testing whether number of twists is 2:
      ({}()<

        # Keep sign/degree on third stack:
        ({}<({}<

          # Duplicate current configuration
          <>({()<({}<>)<>>}<>){({}[()]<(({})<({()<({}<>)<>>})<>>)<>{({}[()]<<>({}<>)>)}{}>)}

        # Push sign and degree on separate stacks
        <>>)<>>)

      # If number of twists is not 2: (i.e., no twists)
      >)((){[()](<{}

        # Make first copy of sign/degree
        (({})<<>(({})<

          # Make second copy of sign/degree
          (<<>({}<<>({}<

            # Do twice:
            (()()){({}[()]<

              # Prepare search for vertex leading into crossing on other side
              ([{}]()<>)

              # While keeping destination on third stack:
              <>({}<

                # Search for matching edge
                <>{({}({})<>[({}<>)])}{}

              # Replace old destination
              {}>)

              # Move back to original stack
              {({}<>)<>}<>

            >)}{}

          # Add orientation to degree
          >{})>)>)

          # Move duplicate to left stack
          <>{}{({}<>)<>}<>

          # Create "fake" edges from current crossing as termination conditions
          ([({}<>)]<((()))>)(())<>

          # Create representation of "top" new edge
          ({}<>)<>{}({}[()])

          # While didn't reach initial crossing again:
          {

            # Keep destination of new edge on third stack
            <>({}<<>

              # Do twice:
              (()()){({}[()]<

                # Search for crossing
                ({}<<>{({}<>)<>}>){({}[({})]<>({}<>))}{}

                # Reverse orientation of crossing
                (({})<<>({}<>)<>([{}])>)

              >)}{}

              # Remove extraneous search term
              {}

            # Push new destination for edge
            >)

            # Set up next edge
            <>({}<(({})())>[()]<>)

          }

          # Get destination of last edge to link up
          {}({}<

            # Find edge headed toward original crossing
            <>{}([{}]()<{({}<>)<>}>){({}({})<>[({}<>)])}

          # Replace destination
          {}{}>)

          # Move everything to left stack
          {({}<>)<>}

          # Clean up temporary data
          <>{}{}{}

        # Push new sign/degree of negatively smoothed knot
        >{})>)

      # Else (two twists)
      # i.e., crossing is the twist in unknot with one half-twist
      >)}{}){(<{}

        # Copy sign and degree+orientation
        (({})<<>(({}{})<

          # Move sign to left stack
          <>(<({}<>)>)

          # Move copy of configuration to left stack
          <>{}{({}<>)<>}

        # Add an additional 4*orientation to degree
        <>>(({}){}){})>)

      >)}

    # Else (one twist)
    >}{}){(<

      # Invert sign and get degree
      {}([{}]<({}<

        # Search term for other edge leading to this crossing
        <>([{}]()<>)

        # With destination on third stack:
        <>({}<

          # Find matching edge
          <>{({}({})<>[({}<>)])}{}

        # Replace destination
        {}>)

        # Move stuff back to left stack
        {({}<>)<>}<>

      # Add 3*orientation to degree
      >({})({}){})>)

    >)}{}

  # Else (no crossings)
  >)}{}){{}

    # If this came from the 2-twist case, undo splitting.
    # If this came from an initial empty input, use implicit zeros to not join anything
    # New sign = sign - 2 * next entry sign
    (([{}]){}<>{}{}<

      # New degree = average of both degrees
      <>({}<>{})

      # Find coefficient corresponding to degree
      {([{}]({}()()<{}({}<>)(())<>>))}{}{}

    # Add sign to coefficient
    {}>{})

    # Move rest of polynomial back to right stack
    (())<>{{}({}<>)(())<>}

    # Set up next configuration
    (<>)<>

  }{}

}{}{}<>{}

# Step 3: Put polynomial in correct form

# Keeping constant term:
{}({}<

  # Move to other stack to get access to terms of highest absolute degree
  {{}({}<>)(())<>}<>

  # Remove outer zeros
  {{}{((<(())>))}{}}

  # Move back to right stack to get access to lower order terms
  {}{{}({}<>)(())<>}

>)<>

# While terms remain:
{

  # Move term with positive coefficient
  {}({}<(<()>)<>([]){{}({}<>)(())<>([])}{}>)<>{{}({}<>)<>}{}

  # Move term with negative coefficient
  {}({}<>)<>

}<>
Nitrodon
źródło
Whoaaaaaa. Fantastyczny!!!! +1
Don Thousand
Czuję, że muszę rozdać kolejną nagrodę
Don Thousand