Code-Golf: pontos de treliça dentro de um círculo


15

A figura a seguir mostra o problema:

insira a descrição da imagem aqui

Escreva uma função que, dado um número inteiro como o raio do círculo, calcule o número de pontos de treliça dentro do círculo centralizado (incluindo o limite).

A imagem mostra:

f[1] = 5  (blue points)
f[2] = 13 (blue + red points)  

outros valores para sua verificação / depuração:

f[3]    = 29
f[10]   = 317
f[1000] = 3,141,549
f[2000] = 12,566,345  

Deve ter um desempenho razoável. Digamos menos de um minuto para f [1000].

O menor código vence. Aplicam-se regras usuais do Código-Golfe.

Por favor, poste o cálculo e o tempo de f [1001] como exemplo.



Respostas:


9

J 21 21 18

+/@,@(>:|@j./~@i:)

Constrói complexos de -x-xj a x + xj e leva magnitude.

Editar: Com >:

Edit 2: Com gancho e monádico ~. É executado algumas vezes mais devagar por algum motivo, mas ainda assim 10 segundos para f (1000).


Oh, ei, eu não sabia i:, estou roubando tanto isso, obrigado!
JB

@JB: Sim, bem ... estou roubando >:. derp
Jesse Millikan

Eu queria entender tampas bem o suficiente para roubar aqueles demasiado O :-)
JB

Esta resposta é deprimente curta (para alguém que nunca se incomodou em aprender um pouco de golfe e / ou golfe) >:. Mas ei, essa é uma resposta legal! :)
Fund Monica's Lawsuit

5

J, 27 21

3 :'+/,y>:%:+/~*:i:y'

Muito brutal: calcula o sqrt (x² + y²) no intervalo [-n, n] e conta os itens ≤n . Tempos ainda muito aceitáveis ​​para 1000.

Edit : i:yé um pouco menor que y-i.>:+:y. Obrigado Jesse Millikan !


Ha! Essa foi a ideia por trás de pedir um desempenho decente! Apenas curioso: qual é o momento para 1000?
amigos estão dizendo sobre belisarius

1
@belisarius: 0.86s. Em hardware de 10 anos. 3.26s para 2000.
JB

4

Ruby 1.9, 62 58 54 caracteres

f=->r{1+4*eval((0..r).map{|i|"%d"%(r*r-i*i)**0.5}*?+)}

Exemplo:

f[1001]
=> 3147833

t=Time.now;f[1001];Time.now-t
=> 0.003361411

4

Python 55 Chars

f=lambda n:1+4*sum(int((n*n-i*i)**.5)for i in range(n))

f=lambda n:1+4*sum(int((n*n-i*i)**.5)for i in range(n))é 17 caracteres menor.
Ventero

3

Haskell, 41 bytes

f n=1+4*sum[floor$sqrt$n*n-x*x|x<-[0..n]]

Conta pontos no quadrante x>=0, y>0, multiplica por 4 e adiciona 1 ao ponto central.


2

Haskell, 44 bytes

f n|w<-[-n..n]=sum[1|x<-w,y<-w,x*x+y*y<=n*n]

Eu sou novo no Haskell: como você pode escrever w<-[-n..n]onde (geralmente) existe um valor booleano?
flawr

1
@flawr Estes são os protetores de padrões , que são bem-sucedidos se um padrão for correspondido, mas podem ser usados ​​no golfe como uma extensão mais curta. Veja esta dica .
Xnor

Obrigado, eu não estava ciente disso esta discussão!
Flawr 13/05/19

1

JavaScript (ES6), 80 bytes (não concorrente porque o ES6 é muito novo)

n=>(a=[...Array(n+n+1)].map(_=>i--,i=n)).map(x=>a.map(y=>r+=x*x+y*y<=n*n),r=0)|r

Versão alternativa, também 80 bytes:

n=>[...Array(n+n+1)].map((_,x,a)=>a.map((_,y)=>r+=x*x+(y-=n)*y<=n*n,x-=n),r=0)|r

Versão ES7, também 80 bytes:

n=>[...Array(n+n+1)].map((_,x,a)=>a.map((_,y)=>r+=(x-n)**2+(y-n)**2<=n*n),r=0)|r

1

Python 2, 48 bytes

f=lambda n,i=0:i>n or(n*n-i*i)**.5//1*4+f(n,i+1)

Como a solução de fR0DDY , mas recursiva, e retorna um float. Retornar um int é de 51 bytes:

f=lambda n,i=0:i>n or 4*int((n*n-i*i)**.5)+f(n,i+1)

1

C (gcc) , 60 bytes

r,a;f(x){for(a=r=x*x;a--;)r-=hypot(a%x+1,a/x)>x;x=4*r+1;}

Experimente online!

Loops sobre o primeiro quadrante, multiplica o resultado por 4 e adiciona um. Um pouco menos golfe

r,a;
f(x){
  for(a=r=x*x;a--;)
    r-=hypot(a%x+1,a/x)>x;
  x=4*r+1;
}

1

APL (Dyalog Extended) , 14 bytes

{≢⍸⍵≥|⌾⍀⍨⍵…-⍵}

Experimente online!

Apesar de não possuir o i:(inclusive intervalo de -n a n) do J, o APL Extended possui uma sintaxe mais curta em outras áreas.

{≢⍸⍵≥|⌾⍀⍨⍵…-⍵}            Monadic function taking an argument n.
           ⍵…-⍵             n, n-1, ..., -n
      ⌾⍀                   Make a table of complex numbers
                            (equivalent to ∘.{⍺+1J×⍵} in Dyalog APL)
                           with both real and imaginary parts from that list.
      |                       Take their magnitudes.
    ⍵≥                        1 where a magnitude are is at most n, and 0 elsewhere.
                            Get all indices of truthy values.
                            Find the length of the resulting list.

1

Japonês -x , 12 bytes

òUn)ï Ëx²§U²

Experimente online!

Explicação:

òUn)            #Get the range [-input ... input]
    ï           #Get each pair of numbers in that range
      Ë         #For each pair:
       x        # Get the sum...
        ²       # Of the squares
         §      # Check if that sum is less than or equal to...
          U²    # The input squared
                #Output the number of pairs that passed the check


1

PHP, 85 83 bytes

O código:

function f($n){for($x=$n;$x;$c+=$x,$y++)for(;$n*$n<$x*$x+$y*$y;$x--);return$c*4+1;}

Seu resultado (consulte https://3v4l.org/bC0cY para várias versões do PHP):

f(1001)=3147833
time=0.000236 seconds.

O código não destruído:

/**
 * Count all the points having x > 0, y >= 0 (a quarter of the circle)
 * then multiply by 4 and add the origin.
 *
 * Walk the lattice points in zig-zag starting at ($n,0) towards (0,$n), in the
 * neighbourhood of the circle. While outside the circle, go left.
 * Go one line up and repeat until $x == 0.
 * This way it checks about 2*$n points (i.e. its complexity is linear, O(n))
 *
 * @param int $n
 * @return int
 */
function countLatticePoints2($n)
{
    $count = 0;
    // Start on the topmost right point of the circle ($n,0), go towards the topmost point (0,$n)
    // Stop when reach it (but don't count it)
    for ($y = 0, $x = $n; $x > 0; $y ++) {
        // While outside the circle, go left;
        for (; $n * $n < $x * $x + $y * $y; $x --) {
            // Nothing here
        }
        // ($x,$y) is the rightmost lattice point on row $y that is inside the circle
        // There are exactly $x lattice points on the row $y that have x > 0
        $count += $x;
    }
    // Four quarters plus the center
    return 4 * $count + 1;
}

Uma implementação ingênua que verifica $n*($n+1)pontos (e roda 1000 mais devagar, mas ainda calcula f(1001)em menos de 0,5 segundos) e o conjunto de testes (usando os dados de amostra fornecidos na pergunta) podem ser encontrados no github .


0

Clojure / ClojureScript, 85 caracteres

#(apply + 1(for[m[(inc %)]x(range 1 m)y(range m):when(<=(+(* x x)(* y y))(* % %))]4))

Brute força o primeiro quadrante, incluindo o eixo y, mas não o eixo x. Gera um 4 para cada ponto e depois os adiciona com 1 para a origem. É executado em menos de 2 segundos para entrada de 1000.

Abusa muito forpara definir uma variável e salvar alguns caracteres. Fazer o mesmo para criar um alias para rangenão salva nenhum caractere (e o torna significativamente mais lento), e parece improvável que você salve algo criando uma função quadrada.


Esta é uma pergunta bastante antiga. Tem certeza de que essa resposta funcionaria na época?
Azul

@muddyfish Não notei a idade, apenas a vi perto do topo. Clojure antecede a pergunta, mas não conheço sua história o suficiente para saber sobre alterações de idioma.
11556 MattPutnam #


0

Mathematica, 35 caracteres

f[n_]:=Sum[SquaresR[2,k],{k,0,n^2}]

Retirado de https://oeis.org/A000328

https://reference.wolfram.com/language/ref/SquaresR.html

SquaresR[2,k]é o número de maneiras de representar k como a soma de dois quadrados, que é o mesmo que o número de pontos de treliça em um círculo de raio k ^ 2. Soma de k = 0 a k = n ^ 2 para encontrar todos os pontos dentro ou dentro de um círculo de raio n.


1
2~SquaresR~k~Sum~{k,0,#^2}&para torná-lo mais curto
jaeyong cantada

0

Tcl, 111 bytes

lassign {1001 0 -1} r R x
while {[incr x]<$r} {set R [expr {$R+floor(sqrt($r*$r-$x*$x))}]}
puts [expr {4*$R+1}]

Loop x discreto simples sobre o quadrante I, contando o maior y usando o Teorema de Pitágoras em cada etapa. O resultado é 4 vezes a soma mais um (para o ponto central).

O tamanho do programa depende do valor de r . Substitua {1001 0 -1}por "$argv 0 -1"e você pode executá-lo com qualquer valor de argumento da linha de comandos para r .

Calcula f (1001) → 3147833.0em cerca de 1030 microssegundos, processador AMD Sempron 130 de 2,6 GHz e 64 bits, Windows 7.

Obviamente, quanto maior o raio, mais próxima a PI: f (10000001) é executada em cerca de 30 segundos, produzindo um valor de 15 dígitos, que é a precisão de um duplo IEEE.


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.