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

D⟨D⟩

wprowadź opis zdjęcia tutaj

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

  2. DDD(−A2−A−2)

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

AA−1

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ść

A−2+5+A−A3[[1,-2],[5,0],[1,1],[-1,3]]

−k…kk∈N[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


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!


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
  {}({}<>)<>

}<>

Whoaaaaaa. Fantastyczny!!!! +1
— Don Thousand

Czuję, że muszę rozdać kolejną nagrodę
— Don Thousand
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.