Baue ein Massenspektrometer!

8

Herausforderung

Geben Sie angesichts der hochauflösenden Molekülmasse eines organischen Moleküls die Molekülformel des Moleküls aus.

Erläuterung

Die Eingabe ist eine einzelne Zahl mit drei Dezimalstellen Genauigkeit, der relativen Molekülmasse des Moleküls.

Hier ist die Molekülmasse als die Summe der Massen der Atome in der Verbindung definiert. Da Sie nur die Molekülformeln organischer Verbindungen finden, müssen Sie folgende Atommassen kennen:

  • C , Kohlenstoff: 12,011
  • H , Wasserstoff: 1,008
  • O , Sauerstoff: 15,999
  • N , Stickstoff: 14.007

Ihre Formel sollte immer nur Kohlenstoff, Wasserstoff, Sauerstoff oder Stickstoff enthalten.

Beim Schreiben der Formel sollte sie folgende Form annehmen:

CaHbOcNd

Wobei die Elemente in dieser Reihenfolge sein muss ( C -> H -> O -> Nso C2O8N4H6sollte sein C2H6O8N4) , und a, b, cund dZahlen sind , des vorhergehenden Elements in dem Molekül ( das heißt C2Mittel , dass es zwei Kohlenstoffatomen im Molekül).

Wenn a, b, coder dNull ist , sollte das Element nicht in der Formel eingeschlossen werden (zB C2H6O2N0soll C2H6O2). Wenn schließlich a, b, coder deins sind, sollten Sie nicht die Nummer in der Formel enthalten (zB C1H4sollte CH4).

Die Eingabe ist immer gültig (dh es gibt ein Molekül mit dieser Masse). Wenn die Eingabe nicht eindeutig ist (mehrere Moleküle haben dieselbe Masse), müssen Sie nur eines der Moleküle ausgeben. Wie Sie dieses Molekül auswählen, liegt bei Ihnen.

Gearbeitetes Beispiel

Angenommen, die Eingabe ist 180.156, dass es nur eine Kombination der Elemente gibt, die diese Molekülmasse haben können:

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

Es gibt also:

  • 6 Kohlenstoffe
  • 12 Wasserstoffatome
  • 6 Sauerstoff
  • 0 Stickstoffatome

Daher sollte Ihre Ausgabe sein:

C6H12O6

Mehr Beispiele

Input -> Output

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

Gewinnen

Der kürzeste Code in Bytes gewinnt.

Beta-Zerfall
quelle
2
Was ist, wenn die Eingabe nicht eindeutig ist?
NoOneIsHere
@NoOneIsHere AFAIK Die Eingabe sollte nicht mehrdeutig sein, aber ich werde das trotzdem in die Regeln aufnehmen.
Beta-Zerfall
Kann Eingabe als int genommen werden (dh keine Periode - Ethen wäre 28054)
Stephen
4
12.011ist die relative Atommasse von Kohlenstoff, die ein gewichteter Durchschnitt der relativen Isotopenmassen der Isotope ist. In einem Massenspektrometer, in dem verschiedene Isotope unterschieden werden, sollten Sie genau sehen 12. Ähnliches gilt für andere Atome.
Undichte Nonne
2
Beachten Sie für einen unterhaltsamen Test, dass der Eingang 672.33624 mögliche Lösungen enthält, darunter eine reine Stickstoff- und eine reine Wasserstofflösung.
Greg Martin

Antworten:

2

Mathematica, 108 Bytes

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

Reine Funktion, die die Eingabe als Ganzzahl erwartet (1000-fache relative Molmasse); Es gibt alle möglichen Antworten auf STOUD aus (und gibt ein Array von Nulls zurück).

Das schwere Heben erfolgt durch das eingebaute Gerät {12011,1008,15999,14007}~FrobeniusSolve~#, das alle nichtnegativen Ganzzahlkombinationen der fest codierten Gewichte findet, die der Eingabe entsprechen. {Characters@"CHON",#}ᵀsetzt jede solche Kombination in eine Form wie {{"C", 0}, {"H", 1}, {"O", 2}, {"N", 3}}. ( ist eigentlich das private 3-Byte-Mathematica-Zeichen U + F3C7.)

Die Transformationsregel /.a_/;Last@a<2:>Table@@aändert Paare des Formulars {x, 0}in {}und Paare des Formulars {x, 1}in {x}(und spuckt Fehler aus, wenn versucht wird, sie auch auf den gesamten Ausdruck anzuwenden). Dann Print@@Join@@gibt das Ergebnis in der richtigen Form, die Notwendigkeit vermieden wird, die ganzen Zahlen als Strings und verketten zu werfen.

Greg Martin
quelle
Was ist das Ergebnis von 672336? :)
Beta Decay
Das scheint der falsche Charakter zu sein. Sollte sein .
Martin Ender
Ja, ich muss die Wahl zwischen einfach zu lesen und einfach auszuschneiden / einfügen treffen.
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)

Probieren Sie es online aus!
Rekursive Funktion, die Eingabe ist eine ganze Zahl (1000-fache der relativen Molekülmasse), danke Stephen S für die Idee


Mein Computer benötigte 40 Segmente, um 672336sich C33H115O3N8mit diesem geänderten Code zu verwandeln . Es enthält eine Nachschlagetabelle für Treffer / Fehler, um die Anzahl der rekursiven Aufrufe zu reduzieren, und eine Optimierung, um ein Element mehrmals zu zählen (wenn die Masse hoch genug ist).

Stange
quelle
Warum tritt eine 180156Zeitüberschreitung auf, wenn alle Testfälle so schnell sind? (ohne den Cache-Treffer)
Beta Decay
@BetaDecay hmm, könnte 18015stattdessen sein?
Rod
Nein, 18015ist H2OnichtC6H12O6
Beta Decay
1

JavaScript (ES6), 159 158 Byte

Nicht gerade schnell ...

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


Schnellere Version, 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``

Alle Testfälle

Arnauld
quelle