Força gravitacional entre números


52

A força gravitacional é uma força que atrai dois objetos com massa. Neste desafio, nossos objetos serão Números e sua massa será seu valor. Para fazer isso, não nos importamos com a força da força, mas com a direção dela.

Imagine esse conjunto de números

[1 6 9 4 6 9 7 6 4 4 9 8 7]

Cada um deles cria uma força entre si e seus números adjacentes. Sob algumas condições, isso fará com que outro número seja atraído (movido) para um número. Quando o número é maior que o adjacente, ele o atrai. Vamos dar uma olhada no nosso exemplo anterior:

[1 → 6 → 9 ← 4 6 → 9 ← 7 ← 6 ← 4 4 → 9 ← 8 ← 7]

O número 1não é grande o suficiente para ser movido 6, mas o número 6é, etc ... Basicamente, os números são movidos para o maior número adjacente (também maior que o próprio número). Se os dois números adjacentes forem iguais, não será atraído. Também acontece quando o número e o adjacente são iguais.

Isso é apenas para mostrar a atração, mas o que acontece depois? Os números que colidem devido à atração são resumidos:

[20 32 28]

Então, basicamente, o desafio é: dado um conjunto de números, produza o resultado do conjunto de números atraído.


Exemplo 1

Input  => [10 15 20 10 20 10 10]
          [10 → 15 → 20 10 20 ← 10 10]
Output => [45 10 30 10]

Exemplo 2

Input  => [9 9 9 9 8 1 8]
          [9 9 9 9 ← 8 1 8]
Output => [9 9 9 17 1 8]

Exemplo 3

Input  => [1 6 9 4 6 9 7 6 4 4 9 8 7]
          [1 → 6 → 9 ← 4 6 → 9 ← 7 ← 6 ← 4 4 → 9 ← 8 ← 7]
Output => [20 32 28]

Exemplo 4

Input  => [1 2 3 2 1]
          [1 → 2 → 3 ← 2 ← 1]
Output => [9]

Exemplo 5

Input  => [1]
Output => [1]

Exemplo 6

Input  => [1 1]
Output => [1 1]

Exemplo 7

Input  => [2 1 4]
Output => [2 5]

Notas

  • A atração acontece apenas uma vez
  • Os números não são atraídos para números não adjacentes
  • O conjunto de números conterá apenas números inteiros positivos

11
Sugira adicionar um caso de teste que seja recolhido em um único número inteiro.
Shaggy

2
[1 3 5 4 2]= 15?
Magic Octopus Urn

@MagicOctopusUrn Sim
Luis felipe De jesus Munoz

14
1 não é grande o suficiente para atrair o número 6 Essa expressão incomoda o físico em mim. (Bem, algumas outras regras também, mas essa pode ser corrigida alterando a redação sem alterar a definição do problema). A força de atração entre dois corpos G*M*m / r^2,, é igual para ambos os corpos. O mais leve se move mais do que o mais pesado por causa do momento, não por falta de atração. Talvez diga "1 não é grande o suficiente para mover 6".
Peter Cordes

4
Mas na verdade você está definindo "atrair" como "puxado em direção a", em vez de "criar uma força", que entra em conflito com a frase anterior " Cada um deles cria uma força de atração para seus números adjacentes ". Então, talvez refaça essa abertura para dizer "cada um deles cria uma força entre si e seus números adjacentes. Sob algumas condições, isso fará com que outro número seja atraído (movido) para um número". Eu sei que isso é apenas um truque de terminologia, e esse modelo de gravitação é apenas vagamente semelhante à física real, mas me incomodou o suficiente para querer escrever esse comentário.
Peter Cordes

Respostas:


15

JavaScript (ES6),  106 104  100 bytes

Guardado 2 bytes graças a @Shaggy

a=>a.filter(n=>n,[...a].map((v,i)=>a[a[p>v&(n=~~a[i+1])<p?k:i+(k=i,n>v&p<n)]+=x=a[i],p=v,i]-=x,p=0))

Experimente online!

Comentado

a[]0 0 .

umaEuumaEu+1 1 sempre que um valor é atraído por seu vizinho direito.

Exemplo: 456[0 0,9,6][0 0,0 0,15] .

umaEuumakk<EuumaEu-1 1 .

654[11,0 0,4][15,0 0,0 0]

[...a]                 // create a copy of a[]
.map((v, i) =>         // for each value v in a[] at position i:
  a[                   //   this statement updates a[i]:
    a[                 //     this statement updates either a[i] or an adjacent value:
      p > v &          //       if the previous value p is greater than v
      (n = ~~a[i + 1]) //       and the next value n
      < p ?            //       is less than p (attraction to the left):
        k              //         use k (k is initially undefined, but this code cannot
                       //         be triggered during the first iteration)
      :                //       else:
        i + (          //         use either i or i + 1:
          k = i,       //           set k to i
          n > v &      //           use i + 1 if n is greater than v
          p < n        //           and p is less than n (attraction to the right)
        )              //
    ] += x = a[i],     //     add x = a[i] to the entry defined above
    p = v,             //     update the previous value to v
    i                  //     actual index to update a[i]
  ] -= x,              //   subtract x from a[i]
  p = 0                //   start with p = 0
)                      // end of map()

0 0

a.filter(n => n)

Pela sua explicação, parece que seu código falharia [1,3,5,3,1,2,1]e emitia [14,2], mas na verdade funciona corretamente e é emitido [13,3].
Erik the Outgolfer

@EriktheOutgolfer Eu reformulei a parte que - eu acho - era enganosa. Isto é melhor?
Arnauld

2
Agora ele menciona o "primeiro atrator" em vez de apenas o "maior valor anterior", para que eu possa entender o que você quer dizer.
Erik the Outgolfer

9

Stax , 27 25 23 18 bytes

«╥╦.ê§┘h!@ÆEÿ☺╜╫♥B

Execute e depure

A saída é separada por novas linhas.

Este programa opera em pares adjacentes na matriz e determina se deve haver uma divisão entre eles usando este procedimento.

Considere alguma entrada arbitrária [... w x y z ...]. Aqui está como determinar se deve haver uma divisão entre xe y.

  • E se x == y sim, então.
  • Se x > y, então sez >= x.
  • Se y > x, então se w >= y.

A soma é deixada como um exercício.


8

Retina 0.8.2 , 64 bytes

\d+
$*
(?<=(1+)) ((?=(1+\1))(?<!\3 \1 )|(?!\1)(?!1+ \1))

1+
$.&

Experimente online! O link inclui o conjunto de testes. Explicação:

\d+
$*

Converta para unário.

(?<=(1+)) ((?=(1+\1))(?<!\3 \1 )|(?!\1)(?!1+ \1))

Remova os separadores entre os números atraídos. (?<=(1+))define \1o número antes do separador. Após o separador, existem dois casos:

  • O número após o separador é maior que os dois números anteriores ao separador
  • O número antes do separador é maior que os dois números após o separador

Nesses casos, há uma atração entre os dois números e a exclusão do separador faz com que os números colidam, juntando-os.

1+
$.&

Converta para decimal.


6

Gelatina , 23 bytes

Ø0jMÆmær0Ʋ3Ƥ×=4$o<ʋƝk⁸§

Experimente online!

Um link monádico que pega uma lista de números inteiros como argumento e retorna uma lista de números inteiros.

Explicação

Ø0j                     | Join [0, 0] with input list
         Ʋ3Ƥ            | For each length 3 infix, do the following as a monad:
   M                    | - Indices of maximum
    Æm                  | - Mean
      ær0               | - Round to even (so the means of [1, 2, 3], [1, 2], [2, 3] and [1, 3] will all round to 2
                  ʋƝ    | For each neighbouring pair, do the following as a dyad:
            ×           | - Multiply
             =4$        | - Check if equal to 4
                o       | - Or
                 <      | - First number less than second
                    k⁸  | Split input after truthy values of the above
                      § | Sum, vectorised

Alguma inspiração tirada da resposta Stax do @ recursive .


4

C (gcc) , 111 bytes

a,b,c,s;P(){s=!printf("%d ",s);}f(int*v){for(b=s=0,c=*v;a=b,b=c;a<b|b<a&c<a||P(),s+=b,b<c&c<=a|!c&&P())c=*++v;}

Experimente online!

Toma uma matriz de números inteiros terminada em zero.

Explicação

a,b,c,  // Three consecutive elements of input array
s;      // Accumulator for sum
P(){s=!printf("%d ",s);}  // Print and clear s
f(int*v){
    for(
        // Init
        b=s=0,
        c=*v;
        // Loop test
        a=b,  // Shift b into a
        b=c;  // Shift c into b, exit if zero
        // Post loop
        a<b|b<a&c<a||P(),  // Print if a==b || (b<a && a<=c)
        s+=b,  // Accumulate
        b<c&c<=a|!c&&P()   // Print if c==0 || (b<c && c<=a)
    )
        // Loop body
        c=*++v;  // Read next number into c
}



3

R , 222 196 173 bytes

Aqui está uma solução com a ajuda de Robin Ryder

n=length(d<-diff(y<-x<-scan()));l=c(1,sign(d[-n]+d[-1]),-1);m=!!l*n&c(d[1]>0,d[-1]>0|d[-n]<0,d[n]<0);for(t in 1:n){for(i in which(m))y[a]=y[a<-i+l[i]]+x[i];y=x=y-x*m};x[!m]

Experimente online!

Um breve conjunto de comentários

n=length(d<-diff(y<-x<-scan()));  #read input and compute pairwise differences
                    #d[-n]+d[-1]: compare left and right differences
l=c(1,sign(d[-n]+d[-1]),-1)                 #direction of attraction
m=!!l*n&                          #indices of attracted numbers
  c(d[1]>0,d[-1]>0|d[-n]<0,d[n]<0)  
                                   #!!l*n eliminates zeroes in l & the case n==0
for(t in 1:n){                   #excessive loop on transfers
 for(i in which(m))
   y[a]=y[a<-i+l[i]]+x[i]         #transfer right vs. left
 y=x=y-m*x}                        #complete transfer
x[!m]                             #output

11
-4 bytes com em sign(e)vez de(e>0)-(e<0)
Robin Ryder

11
também o {}loop for é desnecessário, pois existe apenas uma instrução no loop.
Robin Ryder

11
189 bytes com os 2 comentários acima + movendo a definição de y.
Robin Ryder

11
179 bytes usando o fato de que mé um booleano
Robin Ryder

3

Python, 114 112 bytes

lambda a:eval('['+'+'.join(str(c)+',0'*((e<c>d)==(c<d>b))for b,c,d,e in zip([0]+a,a,a[1:]+[0],a[2:]+[0,0]))+']')

Isso usa o fato de que a direção da seta realmente não importa e que a presença de uma seta entre a [i] e a [i + 1] pode ser determinada observando o intervalo de quatro elementos a [i- 1: i + 3].

Edit: Obrigado a Jo King pelo esclarecimento das regras


2

Perl 5 , 156 147 bytes

$q='$F[$i';map{eval"\$i++while$q]$_"}"<$q+1]",">$q+1]&&$q]>$q+2]&&\$i<\@F"if eval"$q-1]-$q+1]||$q]>$q+1]";$\.=$".sum@F[$p..$i];($p=++$i)<@F&&redo}{

Experimente online!


2

K (ngn / k) , 46 bytes

{+/'x@.={x x}/(!#x)+{-/2=+/x<\:x 2 0}'3'0,x,0}

Experimente online!

0,x,0 rodeie o argumento com 0s

3' trigêmeos de itens consecutivos

{ }' para cada fazer

x 2 0obter o último e o primeiro do trigêmeo atual - x[2]e x[0]. eles são os vizinhos dos x[1]quais o trigêmeo está centrado

x<\: compare usando menos que em relação a cada um dos trigêmeos atuais

+/soma. o resultado é um par correspondente a x[2]ex[0]

2=verifique se um vizinho é maior que os outros 2 elementos x, retorne um par de booleanos 0 ou 1

-/subtraí-los. um resultado de -1 significa que x[1]é atraído para a esquerda, 1 para a direita e 0 significa que permanece no lugar

(!#x)+ adicione 0 ao primeiro item, 1 ao segundo, etc. isso calcula os índices para os quais os itens são atraídos

{x x}/indexe consigo mesmo até a convergência. o resultado são os índices efetivos pelos quais cada item é atraído

x@.= grupo x (o argumento original) por aqueles. o resultado é uma lista de listas

+/' somar cada


2

Clojure , 299 252 bytes

(fn[l](loop[o[0]m(vec(map-indexed(fn[i v](def f #(max(nth l(+ % i)0)v))(-(f -1)(f 1)))l))i 0](defn f[x](update o(-(count o)x)#(+(l i)%)))(cond(<=(count m)i)(pop o)(>(m i)0)(recur(f 2)m(inc i))(<(m i)0)(recur(f 1)m(inc i))1(recur(conj(f 1)0)m(inc i)))))

Experimente online!


Explicação:

(fn [l]
  (loop [o [0]
         m (vec(map-indexed (fn [i v] ; This maps each element l[i] of l to max(l[i-1], l[i]) - max(l[i+1], l[i])
                              (def f #(max (nth l (+ % i) 0) v))
                              (- (f -1) (f 1)))
                            l))       ; l[x] is zero when l[x] is out of bounds of the input vector l
         i 0]
    (defn f [x] (update o (- (count o) x) #(+ (l i) %)))
    ; Defines a function f(x) that returns the result of mapping the (x-1)th to last element of o over the function g(y) = l[i] + y

    (cond
      (<= (count m) i) (pop o) ; If the length of m is less than or equal to i, there are no more elements in m, so return all but the last element of o
      (> (m i) 0) (recur (f 2) m (inc i)) ; If m[i] is positive, l[i] is pulled toward to the previous element, so add l[i] to the 2nd to last element of o
      (< (m i) 0) (recur (f 1) m (inc i)) ; If m[i] is negative, l[i] is pulled toward the next element, so add l[i] to the last element of o
      1 (recur (conj (f 1) 0) m (inc i))))) ; 1 is truthy
      ; If the length of l is less than or equal to i, and m[i] is not positive or negative, we have m[i] = 0, so l[i] is not pulled toward any other element


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.