Construa um espectrômetro de massa!

8

Desafio

Dada a massa molecular de alta resolução de uma molécula orgânica, produz a fórmula molecular da molécula.

Explicação

A entrada será um número único com três casas decimais de precisão, a massa molecular relativa da molécula.

Aqui, a massa molecular é definida como a soma das massas dos átomos no composto. Como você só encontra as fórmulas moleculares dos compostos orgânicos, as massas atômicas que você precisa conhecer são:

  • C , carbono: 12.011
  • H , hidrogênio: 1.008
  • O , oxigênio: 15.999
  • N , nitrogênio: 14.007

Sua fórmula deve sempre conter apenas carbono, hidrogênio, oxigênio ou nitrogênio.

Ao escrever a fórmula, ela deve assumir a forma:

CaHbOcNd

Onde os elementos devem estar nessa ordem ( C -> H -> O -> N, por isso C2O8N4H6deve ser C2H6O8N4) e a, b, ced são números do elemento precedente na molécula (isto é, C2significa que há dois átomos de carbono na molécula).

Se a, b, cou dsão iguais a zero, este elemento não deve ser incluído na fórmula geral (por exemplo, C2H6O2N0deve ser C2H6O2). Finalmente, se a, b, cou dé um, você não deve incluir o número na fórmula (por exemplo, C1H4deve serCH4 ).

A entrada sempre será válida (ou seja, haverá uma molécula com essa massa). Se a entrada for ambígua (várias moléculas têm a mesma massa), você deve produzir apenas uma das moléculas. Como você escolhe esta molécula é com você.

Exemplo Trabalhado

Suponha que a entrada seja 180.156, existe apenas uma combinação dos elementos que podem ter essa massa molecular:

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

Então existem:

  • 6 carbonos
  • 12 Hidrogênios
  • 6 Oxygens
  • 0 nitrogênio

Portanto, sua saída deve ser:

C6H12O6

Mais exemplos

Input -> Output

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

Ganhando

O menor código em bytes vence.

Beta Decay
fonte
2
E se a entrada for ambígua?
NoOneIsHere
@NoOneIsHere AFAIK a entrada não deve ser ambígua, mas adicionarei isso às regras de qualquer maneira.
Beta Decay
A entrada pode ser tomado como int (ou seja, nenhum período - eteno seria 28054)
Stephen
4
12.011é a massa atômica relativa do carbono, que é uma média ponderada das massas isotópicas relativas dos isótopos. Em um espectrômetro de massa, onde diferentes isótopos são distinguidos, você deve ver exatamente 12. Semelhante para outros átomos.
Leaky Nun
2
Para um teste divertido, observe que a entrada 672.336possui 24 soluções possíveis, incluindo uma solução de nitrogênio puro e uma de hidrogênio puro.
Greg Martin

Respostas:

2

Mathematica, 108 bytes

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

Função pura, esperando a entrada como um número inteiro (1000 vezes a massa molecular relativa); imprime todas as respostas possíveis para STOUD (e retorna uma matriz de Nulls).

O trabalho pesado é feito pelo built-in {12011,1008,15999,14007}~FrobeniusSolve~#, que encontra todas as combinações inteiras não-negativas dos pesos codificados que são iguais à entrada. {Characters@"CHON",#}ᵀcoloca cada combinação em uma forma como {{"C", 0}, {"H", 1}, {"O", 2}, {"N", 3}}. ( na verdade, é o caractere privado do Mathematica de 3 bytes U + F3C7.)

A regra de transformação /.a_/;Last@a<2:>Table@@aaltera pares do formulário {x, 0}para {}e pares do formulário {x, 1}para {x}(e cospe erros ao tentar aplicar-se a toda a expressão). Em seguida, Print@@Join@@imprime o resultado na forma correta, evitando a necessidade de converter os números inteiros como seqüências de caracteres e concatenar.

Greg Martin
fonte
Qual é o resultado de 672336? :)
Decay Beta
A parece ser o personagem errado. Deveria ser .
Martin Ender
Sim, tem que fazer a escolha entre fácil de ler e fácil de cortar / colar.
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)

Experimente online!
Função recursiva, a entrada é um número inteiro (1000 vezes a massa molecular relativa), graças a Stephen S pela ideia


Minha máquina levou 40 segs para ligar 672336para C33H115O3N8com este código modificado . Ele contém uma tabela de pesquisa de ocorrências / falhas para reduzir a quantidade de chamadas recursivas e uma otimização para contar um elemento várias vezes (se a massa for alta o suficiente)

Cajado
fonte
Por que o 180156tempo limite é excedido quando todos os casos de teste são tão rápidos? (sem o acerto do cache)
Decay Beta
@BetaDecay hmm, poderia ser 18015?
Rod
Não, 18015é H2O, nãoC6H12O6
Beta Decay
1

JavaScript (ES6), 159 158 bytes

Não é exatamente 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``

Demo


Versão mais 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 os casos de teste

Arnauld
fonte