Numéroter les justifications positives


14

Les nombres rationnels positifs peuvent être montrés numérotables avec le processus suivant:

  1. Zéro a l'ordinal 0
  2. Disposez les autres nombres dans une grille de sorte que la ligne a, la colonne b contienne a / b
  3. Tracer un zigzag diagonal en haut à droite en bas à gauche
  4. Gardez un décompte des nombres uniques rencontrés le long du zig-zag

Voici une photo du zig-zag:

Commencer à 1/1, mouvement initial à droite

Ainsi, les nombres rencontrés sont, afin

1/1, 2/1, 1/2, 1/3, 2/2, 3/1, 4/1, 3/2, 2/3, 1/4, 1/5, 2/4, 3/3, 4/2, 5/1, 6/1, 5/2, 4/3, 3/4, 2/5, 1/6, 1/7, 2/6, 3/5, 4/4, 5/3 ...

Et les nombres uniques et simplifiés rencontrés sont

1, 2, 1/2, 1/3, 3, 4, 3/2, 2/3, 1/4, 1/5, 5, 6, 5/2, 4/3, 3/4, 2/5, 1/6, 1/7, 3/5, 5/3, ...

Défi:

  • Étant donné deux entiers supérieurs à zéro p et q , afficher le nombre ordinal de p / q
  • p et q ne sont pas nécessairement co-amorces
  • Victoires de code les plus courtes
  • Les failles standard sont interdites

Cas de test:

Voici les 24 premiers nombres rationnels rencontrés et la sortie souhaitée pour chacun:

1/1: 1
2/1: 2
1/2: 3
1/3: 4
2/2: 1
3/1: 5
4/1: 6
3/2: 7
2/3: 8
1/4: 9
1/5: 10
2/4: 3
3/3: 1
4/2: 2
5/1: 11
6/1: 12
5/2: 13
4/3: 14
3/4: 15
2/5: 16
1/6: 17
1/7: 18
2/6: 4
3/5: 19

Et, pour d'autres cas de test, voici les 200 premiers nombres rationnels positifs dans l'ordre:

1, 2, 1/2, 1/3, 3, 4, 3/2, 2/3, 1/4, 1/5, 
5, 6, 5/2, 4/3, 3/4, 2/5, 1/6, 1/7, 3/5, 5/3, 
7, 8, 7/2, 5/4, 4/5, 2/7, 1/8, 1/9, 3/7, 7/3, 
9, 10, 9/2, 8/3, 7/4, 6/5, 5/6, 4/7, 3/8, 2/9, 
1/10, 1/11, 5/7, 7/5, 11, 12, 11/2, 10/3, 9/4, 8/5, 
7/6, 6/7, 5/8, 4/9, 3/10, 2/11, 1/12, 1/13, 3/11, 5/9, 
9/5, 11/3, 13, 14, 13/2, 11/4, 8/7, 7/8, 4/11, 2/13, 
1/14, 1/15, 3/13, 5/11, 7/9, 9/7, 11/5, 13/3, 15, 16, 
15/2, 14/3, 13/4, 12/5, 11/6, 10/7, 9/8, 8/9, 7/10, 6/11, 
5/12, 4/13, 3/14, 2/15, 1/16, 1/17, 5/13, 7/11, 11/7, 13/5, 
17, 18, 17/2, 16/3, 15/4, 14/5, 13/6, 12/7, 11/8, 10/9, 
9/10, 8/11, 7/12, 6/13, 5/14, 4/15, 3/16, 2/17, 1/18, 1/19, 
3/17, 7/13, 9/11, 11/9, 13/7, 17/3, 19, 20, 19/2, 17/4, 
16/5, 13/8, 11/10, 10/11, 8/13, 5/16, 4/17, 2/19, 1/20, 1/21, 
3/19, 5/17, 7/15, 9/13, 13/9, 15/7, 17/5, 19/3, 21, 22, 
21/2, 20/3, 19/4, 18/5, 17/6, 16/7, 15/8, 14/9, 13/10, 12/11, 
11/12, 10/13, 9/14, 8/15, 7/16, 6/17, 5/18, 4/19, 3/20, 2/21, 
1/22, 1/23, 5/19, 7/17, 11/13, 13/11, 17/7, 19/5, 23, 24, 
23/2, 22/3, 21/4, 19/6, 18/7, 17/8, 16/9, 14/11, 13/12, 12/13, 
11/14, 9/16, 8/17, 7/18, 6/19, 4/21, 3/22, 2/23, 1/24, 1/25 

Criez à la question inverse , où le premier mouvement est en baisse afin que vous ne puissiez pas utiliser les réponses pour générer des cas de test supplémentaires.


Je me demande s'il existe des schémas de numérotation alternatifs qui rendent le code plus court.
qwr

1
Numérateurs de fractions: oeis.org/A157807 dénominateurs: oeis.org/A157813 Aucun résultat pour la séquence ordinale: oeis.org/…
qwr

je vois. vous devez réduire la fraction puis compter. ce n'est pas seulement le zig-zag
don bright

Réponses:


4

Gelée ,  21  20 octets

Probablement battable par un certain nombre d'octets en utilisant des mathématiques intelligentes ...

:g/
ǵSRRUĖ€UÐeẎÇ€Qi

Un lien monadique acceptant une liste [p,q]qui renvoie le nombre naturel attribué à p/q.

Essayez-le en ligne! Ou consultez la suite de tests .

Comment?

Notez d'abord que le N e diagonale rencontrée contient tous les nombres rationnels de la grille pour lesquels la somme du numérateur et du dénominateur est égale à N + 1 , donc étant donné une fonction qui réduit une [p,q]paire à la forme la plus simple ( [p/gcd(p,q),q/gcd(p,q)]), nous pouvons construire les diagonales aussi loin que doit être *, réduire toutes les entrées, dédoublonner et trouver l'index de l'entrée simplifiée.

* en fait un autre ici pour enregistrer un octet

:g/ - Link 1, simplify a pair: list of integers, [a, b]
  / - reduce using:
 g  - Greatest Common Divisor -> gcd(a, b)
:   - integer division (vectorises) -> [a/gcd(a,b), b/gcd(a,b)]

ǵSRRUĖ€UÐeẎÇ€Qi - Main Link: list of integers, [p, q]
Ç                - call last Link as a monad (simplify)
 µ               - start a new monadic chain (call that V)
  S              - sum -> the diagonal V will be in plus one
   R             - range -> [1,2,3,...,diag(V)+1]
    R            - range (vectorises) -> [[1],[1,2],[1,2,3],...,[1,2,3,...,diag(V)+1]]
     U           - reverse each       -> [[1],[2,1],[3,2,1],[diag(V)+1,...,3,2,1]]
      Ė€         - enumerate €ach     -> [[[1,1]],[[1,2],[2,1]],[[1,3],[2,2],[3,1]],[[1,diag(V)+1],...,[diag(V)-1,3],[diag(V),2],[diag(V)+1,1]]]
         Ðe      - apply only to the even indexed items:
        U        -   reverse each     -> [[[1,1]],[[2,1],[1,2]],[[1,3],[2,2],[3,1]],[[4,1],[3,2],[2,3],[1,4]],...]
           Ẏ     - tighten            -> [[1,1],[2,1],[1,2],[1,3],[2,2],[3,1],[4,1],[3,2],[2,3],[1,4],...]
            Ç€   - for €ach: call last Link as a monad (simplify each)
                 -                    -> [[1,1],[2,1],[1,2],[1,3],[1,1],[3,1],[4,1],[3,2],[2,3],[1,4],...]
              Q  - de-duplicate       -> [[1,1],[2,1],[1,2],[1,3],[3,1],[4,1],[3,2],[2,3],[1,4],...]
               i - index of V in that list

3

Perl 6 ,  94  90 octets

->\p,\q{(({|(1…($+=2)…1)}…*)Z/(1,{|(1…(($||=1)+=2)…1)}…*)).unique.first(p/q,:k)+1}

Essaye-le

{(({|(1…($+=2)…1)}…*)Z/(1,{|(1…(($||=1)+=2)…1)}…*)).unique.first($^p/$^q):k+1}

Essaye-le

Cela génère essentiellement la séquence entière de valeurs et s'arrête lorsqu'il trouve une correspondance.

Étendu:

{  # bare block lambda with placeholder parameters $p,$q

  (
      ( # sequence of numerators

        {
          |( # slip into outer sequence (flatten)

            1      # start at one
            
            (
              $    # state variable
              += 2 # increment it by two each time this block is called
            )
            
            1      # finish at one
          )

        }
         * # never stop generating values
      )


    Z/   # zip using &infix:« /  » (generates Rats)


      ( # sequence of denominators

        1,  # start with an extra one

        {
          |( # slip into outer sequence (flatten)

            1
            
            (
              ( $ ||= 1 ) # state variable that starts with 1 (rather than 0)
              += 2        # increment it by two each time this is called
            )
            
            1
          )
        }
         * # never stop generating values
      )


  ).unique            # get only the unique values
  .first( $^p / $^q ) # find the first one that matches the input
  :k                  # get the index instead (0 based)
  + 1                 # add one               (1 based)
}

({1…($+=2)…1}…*)génère la séquence infinie de numérateurs ( |(…)est utilisé ci-dessus pour aplatir)

(1 2 1)
(1 2 3 4 3 2 1)
(1 2 3 4 5 6 5 4 3 2 1)
(1 2 3 4 5 6 7 8 7 6 5 4 3 2 1)
(1 2 3 4 5 6 7 8 9 10 9 8 7 6 5 4 3 2 1)

(1,{1…(($||=1)+=2)…1}…*) génère la séquence infinie de dénominateurs

1
(1 2 3 2 1)
(1 2 3 4 5 4 3 2 1)
(1 2 3 4 5 6 7 6 5 4 3 2 1)
(1 2 3 4 5 6 7 8 9 8 7 6 5 4 3 2 1)
(1 2 3 4 5 6 7 8 9 10 11 10 9 8 7 6 5 4 3 2 1)

3

Python 2 , 157 144 137 134 126 125 125 octets

def f(p,q):a=[((j-i)/(i+1.))**(j%-2|1)for j in range(p-~q)for i in range(j)];return-~sorted(set(a),key=a.index).index(p*1./q)

Essayez-le en ligne!

4 octets enregistrés grâce à M. Xcoder ; 1 octet de Jonathon Frech .

Comme l'a noté M. Xcoder, nous pouvons faire un peu mieux en Python 3 car, entre autres, la division entière par défaut est flottante, et nous pouvons plus facilement décompresser lists:

Python 3 , 117 octets

def f(p,q):a=[((j-i)/-~i)**(j%-2|1)for j in range(p-~q)for i in range(j)];return-~sorted({*a},key=a.index).index(p/q)

Essayez-le en ligne!


128 octets (-6) en échangeant la fraction et en utilisant **(j%-2|1)et p-~q.
M. Xcoder

@Monsieur. Xcoder: Vous êtes tout au sujet du modulo négatif aujourd'hui! :) Je pense que j'ai encore besoin du +1à la fin, car 1,1«doit» donner 1, non 0.
Chas Brown


124 octets :) Oui, le modulo négatif s'avère vraiment utile!
M. Xcoder


3

Python 3 ,157, 146, 140, 133 octets

def f(p,q):a=[(i+i-abs(j-i-i))/(abs(j-i-i+.5)+.5)for i in range(p+q)for j in range(4*i)];return sorted(set(a),key=a.index).index(p/q)

Essayez-le en ligne!

a gagné 11 octets grâce à Jonathan Frech

gagné 6 octets de plus puis 7 grâce à Chas Brown




@bobrobbob: Bienvenue chez PPCG! Je ne sais pas trop comment fonctionne votre algorithme (bien qu'il le fasse clairement); mais expérimentalement, il semble que vous pouvez économiser quelques octets supplémentaires en les remplaçant range(max(p,q)+1)par range(p+q).
Chas Brown

1
Vous pouvez enregistrer quelques octets supplémentaires en utilisant {*a}au lieu de set(a).
M. Xcoder

2

J, 41 , 35 , 30 octets

-11 octets grâce à FrownyFrog

%i.~0~.@,@,[:]`|./.[:%/~1+i.@*

Essayez-le en ligne!

message original de 41 octets avec explication

%>:@i.~[:([:~.@;[:<@|.`</.%"1 0)~(1+i.@*)

non golfé

% >:@i.~ [: ([: ~.@; [: <@|.`</. %"1 0)~ 1 + i.@*

explication

                  +
                  | Everything to the right of this
                  | calculates the list
p (left arg)      |                                      create the
divided by q      |                                      diagonals.  yes,
      (right)     |                                     +this is a         +create this list
   |              |        ++ finally rmv ^alternately  |primitive ADVERB  |1..(p*q), and pass
   |   + the index          | the boxes,  |box, or      |in J              |it as both the left
   |   | of that  |         | and remove  |reverse and  |                  |and right arg to the
   |   | in the   |         | any dups    |box, each    |                  |middle verb, where each
   |   | list on  |         |             |diagonal     |                  |element will divide the
   |   | the right|         |             |             |       +----------+entire list, producing
   |   | plus 1   |         |             |             |       |          |the undiagonalized grid
   |   |          |         |             |             |       |          |
   |   |          |         |             |             |       |          |
   |   |          +         |             |             |       |          |
  ┌+┬──|──────────┬─────────|─────────────|─────────────|───────|──────────|─────────────┐
  │%│┌─+───────┬─┐│┌──┬─────|─────────────|─────────────|───────|────────┬─|────────────┐│
  │ ││┌──┬─┬──┐│~│││[:│┌────|─────────────|─────────────|───────|─────┬─┐│┌+┬─┬────────┐││
  │ │││>:│@│i.││ │││  ││┌──┬|───────┬─────|─────────────|───────|────┐│~│││1│+│┌──┬─┬─┐│││
  │ ││└──┴─┴──┘│ │││  │││[:│+──┬─┬─┐│┌──┬─|─────────────|─┬─────|───┐││ │││ │ ││i.│@│*││││
  │ │└─────────┴─┘││  │││  ││~.│@│;│││[:│┌|───────────┬─+┐│┌─┬─┬+──┐│││ │││ │ │└──┴─┴─┘│││
  │ │             ││  │││  │└──┴─┴─┘││  ││+────────┬─┐│/.│││%│"│1 0││││ ││└─┴─┴────────┘││
  │ │             ││  │││  │        ││  │││┌─┬─┬──┐│<││  ││└─┴─┴───┘│││ ││              ││
  │ │             ││  │││  │        ││  ││││<│@│|.││ ││  ││         │││ ││              ││
  │ │             ││  │││  │        ││  │││└─┴─┴──┘│ ││  ││         │││ ││              ││
  │ │             ││  │││  │        ││  ││└────────┴─┘│  ││         │││ ││              ││
  │ │             ││  │││  │        ││  │└────────────┴──┘│         │││ ││              ││
  │ │             ││  │││  │        │└──┴─────────────────┴─────────┘││ ││              ││
  │ │             ││  ││└──┴────────┴────────────────────────────────┘│ ││              ││
  │ │             ││  │└──────────────────────────────────────────────┴─┘│              ││
  │ │             │└──┴──────────────────────────────────────────────────┴──────────────┘│
  └─┴─────────────┴──────────────────────────────────────────────────────────────────────┘

Essayez-le en ligne!


35:1+~.@;@([:<@|.`</.%~/~)@(1+i.@*)i.%
FrownyFrog

Merci, très gentil! je le
Jonah

Et 30:%i.~0~.@,@,[:]`|./.[:%/~1+i.@*
FrownyFrog

c'est intelligent, utilisez 0 et ~. pour éviter la boxe et l'incrément, j'adore
Jonah

2

Python 3, 121 octets

import math
def o(x,y):
 p=q=n=1
 while x*q!=p*y:a=p+q&1;p+=1+a*~-~-(p<2);q+=1-~-a*~-~-(q<2);n+=math.gcd(p,q)<2
 return n

2

Rouille, 244 octets

J'ai créé une formule simple pour trouver l'ordinal "simple" d'un zigzag "simple", sans les contraintes du puzzle, en utilisant des formules de nombres triangulaires: https://www.mathsisfun.com/algebra/triangular-numbers.html . Cela a été modifié avec modulo 2 pour tenir compte des zig-zags inversant leur direction chaque rangée diagonale du puzzle. C'est la fonction h ()

Ensuite, pour l'astuce principale de ce puzzle: comment `` ne pas compter '' certaines valeurs répétitives, comme 3/3 vs 1/1, 4/2 vs 2/1, dans la piste en zig-zag. J'ai exécuté les exemples 1 à 200 et j'ai remarqué la différence entre un compteur triangulaire en zig-zag simple et celui que le puzzle souhaite, a un motif. Le schéma des nombres "manquants" est 5, 12, 13, 14, 23, etc., ce qui a entraîné un coup dans l'OEIS. Il s'agit de celui décrit par Robert A Stump, à https://oeis.org/A076537 , afin de "dédupliquer" les nombres comme 3/3, 4/2 et 1/1, vous pouvez vérifier si GCD> 1 pour le x, y de tous les ordinaux "précédents" dans le zigzag. Ce sont les boucles 'for' et g () qui est le gcd.

Je suppose qu'avec un gcd intégré, il aurait été plus court, mais je ne pouvais pas en trouver un très facilement (je suis un peu nouveau chez Rust et Integer m'a confondu), et j'aime le fait que celui-ci utilise l'arithmétique entière directe, et aucun buildins ou bibliothèques d'aucune sorte.

fn f(x:i64,y:i64)->i64 {
        fn h(x:i64,y:i64)->i64 {let s=x+y;(s*s-3*s+4)/2-1+(s+1)%2*x+s%2*y}
        fn g(x:i64,y:i64)->i64 {if x==0 {y} else {g(y%x,x)}}
        let mut a=h(x,y);
        for i in 1..x+y {for j in 1..y+x {if h(i,j)<h(x,y) && g(i,j)>1 {a-=1;}}}
        a
}

1

JavaScript (ES6), 86 octets

Prend des entrées dans la syntaxe de curry (p)(q).

p=>q=>(g=x=>x*y?x*q-y*p?g(x+d,g[x/=y]=g[x]||++n,y-=d):n:g(x+!~d,y+=!~(d=-d)))(d=n=y=1)

Essayez-le en ligne!


0

Javascript, 79 octets

a=(p,q)=>p*q==1?1:1+((p+q)%2?q==1?a(p-1,q):a(p+1,q-1):p==1?a(p,q-1):a(p-1,q+1))

(Je suis nouveau dans le golf de code, donc cela peut probablement être amélioré facilement)

Explication

let a = (p, q) => p * q == 1 // If they are both 1
    ? 1
    // Do a recursive call and increment the result by 1
    : 1 + (
        (p + q) % 2 // If on an even-numbered diagonal
        ? q == 1 // If at the beginning of the diagonal
            ? a(p - 1, q) // Go to previous diagonal
            : a(p + 1, q - 1) // Go one back
        : p == 1 // rougly the same
            ? a(p, q - 1)
            : a(p - 1, q + 1)
    )

4
(3,5)devrait entraîner 19(non 24) depuis (1,1)==(2,2)==(3,3), (2,4)==(1,2), (4,2)==(2,1)et (2,6)==(1,3). (c.-à-d. que cela (2,2)devrait se traduire par 1non 5, etc ...)
Jonathan Allan
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.