¡Construye un espectrómetro de masas!

8

Desafío

Dada la masa molecular de alta resolución de una molécula orgánica, genera la fórmula molecular de la molécula.

Explicación

La entrada será un solo número con tres decimales de precisión, la masa molecular relativa de la molécula.

Aquí, la masa molecular se define como la suma de las masas de los átomos en el compuesto. Como solo está encontrando las fórmulas moleculares de los compuestos orgánicos, las masas atómicas que necesita saber son:

  • C , carbono: 12.011
  • H , hidrógeno: 1.008
  • O , oxígeno: 15.999
  • N , nitrógeno: 14.007

Su fórmula solo debe contener carbono, hidrógeno, oxígeno o nitrógeno.

Al escribir la fórmula, debe tomar la forma:

CaHbOcNd

Cuando los elementos deben estar en ese orden ( C -> H -> O -> N, por lo que C2O8N4H6debe ser C2H6O8N4) y a, b, cy dson números del elemento precedente en la molécula (es decir, C2significa que hay dos átomos de carbono en la molécula).

Si a, b, co dson cero, ese elemento no debería incluirse en la fórmula (por ejemplo, C2H6O2N0debe ser C2H6O2). Por último, si a, b, co dson uno, no debería incluir el número en la fórmula (por ejemplo, C1H4debería ser CH4).

La entrada siempre será válida (es decir, habrá una molécula con esa masa). Si la entrada es ambigua (varias moléculas tienen la misma masa), solo debe generar una de las moléculas. Cómo elige esta molécula depende de usted.

Ejemplo trabajado

Supongamos que la entrada es 180.156, solo hay una combinación de los elementos que pueden tener esta masa molecular:

12.011*6 + 1.008*12 + 15.999*6 + 14.007*0 = 180.156

Entonces hay:

  • 6 carbonos
  • 12 hidrógenos
  • 6 oxígenos
  • 0 Nitrógenos

Por lo tanto, su salida debería ser:

C6H12O6

Más ejemplos

Input -> Output

28.054 -> C2H4
74.079 -> C3H6O2
75.067 -> C2H5O2N
18.015 -> H2O

Victorioso

El código más corto en bytes gana.

Decaimiento Beta
fuente
2
¿Qué pasa si la entrada es ambigua?
NoOneIsHere
@NoOneIsHere AFAIK la entrada no debe ser ambigua, pero de todos modos agregaré eso a las reglas.
Beta Decay
De entrada puede ser tomado como int (es decir, sin periodo de - eteno sería 28054)
Stephen
44
12.011es la masa atómica relativa de carbono, que es un promedio ponderado de las masas isotópicas relativas de los isótopos. En un espectrómetro de masas, donde se distinguen diferentes isótopos, debería ver exactamente 12. Similar para otros átomos.
Leaky Nun
2
Para una prueba divertida, tenga en cuenta que la entrada 672.336tiene 24 soluciones posibles, incluida una solución de nitrógeno puro y una de hidrógeno puro.
Greg Martin

Respuestas:

2

Mathematica, 108 bytes

Print@@Join@@({Characters@"CHON",#}ᵀ/.a_/;Last@a<2:>Table@@a)&/@{12011,1008,15999,14007}~FrobeniusSolve~#&

Función pura que espera la entrada como un entero (1000 veces la masa molecular relativa); imprime todas las respuestas posibles a STOUD (y devuelve una serie de Nulls).

El levantamiento pesado lo realiza el builtin {12011,1008,15999,14007}~FrobeniusSolve~#, que encuentra todas las combinaciones enteras no negativas de los pesos codificados que son iguales a la entrada. {Characters@"CHON",#}ᵀpone cada una de esas combinaciones en una forma como {{"C", 0}, {"H", 1}, {"O", 2}, {"N", 3}}. (en realidad es el carácter privado de 3 bytes de Mathematica U + F3C7).

La regla de transformación /.a_/;Last@a<2:>Table@@acambia los pares de la forma {x, 0}a{} y los pares del formulario {x, 1}a {x}(y escupe errores a medida que intenta aplicarse también a toda la expresión). Luego Print@@Join@@imprime el resultado en la forma correcta, evitando la necesidad de convertir los enteros como cadenas y concatenar.

Greg Martin
fuente
¿Cuál es el resultado de 672336? :)
Beta Decay
El parece ser el personaje equivocado. Debe ser .
Martin Ender
Sí, tengo que elegir entre fácil de leer y fácil de cortar / pegar.
Greg Martin
2

Python 2 , 242 bytes

b=[12011,1008,15999,14007]
def p(m):
 if m in b:x=[0,]*4;x[b.index(m)]=1;return x
 elif m<1:return 0
 else:
  for i in range(4):
   x=p(m-b[i])
   if x:x[i]+=1;return x
  return 0
print''.join(a+`n`*(n>1)for n,a in zip(p(input()),'CHON')if n)

Pruébalo en línea!
Función recursiva, la entrada es un número entero (1000 veces la masa molecular relativa) gracias Stephen S por la idea


Mi máquina tomó 40 segs a su vez 672336en C33H115O3N8con este código modificado . Contiene una tabla de búsqueda de aciertos / errores para reducir la cantidad de llamadas recursivas y una optimización para contar un elemento varias veces (si la masa es lo suficientemente alta)

varilla
fuente
¿Por qué se agota el 180156tiempo de espera cuando todos los casos de prueba son tan rápidos? (sin el aciertos de caché)
Decaimiento beta
@BetaDecay hmm, ¿podría ser 18015en su lugar?
Rod
No, 18015es H2O, noC6H12O6
Beta Decay
1

JavaScript (ES6), 159158 bytes

No exactamente rápido ...

w=>[...Array(w**4|0)].some((_,n)=>![12011,1008,15999,14007].reduce((p,c,i)=>p-c*(x[i]=n%w|!(n/=w)),w*1e3,x=[]))&&x.map((v,i)=>('CHON'[i]+v).slice(0,v)).join``

Manifestación


Versión más rápida, 174 173 bytes

w=>[...Array(w**3|0)].some((_,n)=>r=(d=w*1e3-14007*(a=n/w/w%w|0)-15999*(b=n/w%w|0)-12011*(c=n%w|0))%1008|d<0?0:[c,d/1008,b,a])&&r.map((v,i)=>('CHON'[i]+v).slice(0,v)).join``

Todos los casos de prueba

Arnauld
fuente