Machen Sie die Quadratwurzeln rückgängig

16

Ihre Aufgabe ist es, Dezimalstellen in die Summe der Quadratwurzeln von ganzen Zahlen umzuwandeln. Das Ergebnis muss eine Genauigkeit von mindestens 6 signifikanten Dezimalstellen haben.

Eingabe :

Eine Zahl, die die Anzahl der Quadratwurzeln angibt, und eine Dezimalzahl, die die ungefähre Anzahl angibt.

Beispiel Eingabe:

2 3.414213562373095

Ausgabe : Ganzzahlen, die durch Leerzeichen getrennt sind und bei Quadratwurzelbildung und Addition ungefähr die ursprüngliche Dezimalstelle darstellen, mit einer Genauigkeit von mindestens 6 signifikanten Dezimalstellen.

Nullen sind in der Lösung nicht zulässig.

Wenn es mehrere Lösungen gibt, müssen Sie nur eine drucken.

Beispielausgabe (in beliebiger Reihenfolge):

4 2

Das funktioniert weil Math.sqrt(4) + Math.sqrt(2) == 3.414213562373095.

Das ist Code Golf. Der kürzeste Code (mit optionalem Bonus) gewinnt!

Es wird immer eine Lösung geben, aber -10, wenn Ihr Programm "Nein" ausgibt, wenn es keine Lösung mit ganzen Zahlen gibt. Außerdem -10, wenn Ihr Programm alle Lösungen (durch Zeilenumbrüche oder Semikolons oder was auch immer getrennt) anstelle von nur einer ausgibt.

Testfälle:

3 7.923668178593959 --> 6 7 8
2 2.8284271247461903 --> 2 2
5 5.0 --> 1 1 1 1 1
5 13.0 --> 4 4 9 9 9 --> 81 1 1 1 1 --> 36 9 4 1 1 etc. [print any, but print all for the "all solutions bonus"]

Und ja, Ihr Programm muss in endlicher Zeit mit endlichem Speicher auf jedem vernünftigen Computer beendet werden. Es kann nicht nur "theoretisch" funktionieren, man muss es auch tatsächlich testen können.

soktinpk
quelle
Wenn es mehrere Lösungen gibt, spielt es dann eine Rolle, welche Lösung wir drucken? ZB für Ihren letzten Testfall (5 13.0) ist dies auch eine gültige Lösung: 81 1 1 1 1
Jakube
Und sind Nullen in der Lösung erlaubt?
Jakube
1
Ist die Eingabe immer durch Leerzeichen getrennt?
Sp3000
Und ist die Eingabe per Funktionsaufruf erlaubt?
Jakube
Was ist mit doppelten Lösungen? Darf unser Code im ersten Beispiel alle sechs Permutationen des 6 7 8zweiten Bonus drucken ?
Martin Ender

Antworten:

9

Python 3, 90 - 10 = 80

def S(N,x,n=[],i=1):
 if x*x<1e-12>N==0:print(*n)
 while.1+x*x>i:S(N-1,x-i**.5,n+[i]);i+=1

(Mega danke an @xnor für Tipps, insbesondere die Umstrukturierung der for-Schleife in eine Weile)

Ein einfacher rekursiver Versuch. Es beginnt mit der Zielzahl und subtrahiert kontinuierlich Quadratwurzeln, bis es 0 oder weniger erreicht. Die Funktion Skann wie S(2,3.414213562373095)folgt aufgerufen werden (das zweite Argument wird als positiv angenommen).

Das Programm druckt nicht nur alle Lösungen aus, es druckt auch alle Permutationen von Lösungen aus (etwas irrelevant, ich weiß). Hier ist die Ausgabe für den letzten Fall: Pastebin .

Eine leichte Änderung ergibt eine 98 - 10 = 88- Lösung, die keine Permutationen druckt, wodurch sie effizienter wird:

def S(N,x,n=[]):
 *_,i=[1]+n
 if x*x<1e-12>N==0:print(*n)
 while.1+x*x>i:S(N-1,x-i**.5,n+[i]);i+=1

Und nur zum Spaß, diese 99 - 10 = 89 ist ungefähr so ​​effizient wie es nur geht (im Gegensatz zu den anderen sprengt es nicht den Stapel auf S(1,1000):

def S(N,x,n=[]):
 *_,i=[1]+n
 if x*x<1e-12>N:print(*n)
 while(.1+x*x>i)*N:S(N-1,x-i**.5,n+[i]);i+=1

Beachten Sie, dass, obwohl wir ein veränderbares Standardargument haben, dies niemals ein Problem verursacht, wenn wir die Funktion erneut ausführen, da n+[i]eine neue Liste erstellt wird.


Beweis der Richtigkeit

Um in eine Endlosschleife zu gelangen, müssen wir einen Punkt erreichen, an dem x <0 und 0.1 + x 2 > 1 . Dies wird durch x <-0.948 ... erfüllt .

Beachten Sie jedoch, dass wir mit positivem x beginnen und x immer kleiner wird. Um also x <-0,948 zu treffen, müssen wir x '- i 0,5 <-0,948 ... für einige x'> -0,948 haben. . vor x und positive ganze Zahl i . Damit die while-Schleife ausgeführt werden kann, muss auch 0.1 + x ' 2 > i vorliegen .

Beim Umordnen erhalten wir x ' 2 + 1.897x' + 0.948 <i <0.1 + x ' 2 , wobei die äußeren Teile bedeuten , dass x' <-0.447 . Aber wenn -0,948 <x '<-0,447 , dann kann keine positive ganze Zahl i in die Lücke in der obigen Ungleichung passen.

Daher werden wir niemals in eine Endlosschleife geraten.

Sp3000
quelle
Sie können vermeiden , absmit x*x<1e-12.
26.
1
Ich denke , diese whileSchleife zu ersetzen funktioniert das for: while.1+x*x>i:S(x-i**.5,n+[i]);i+=1, initialisiert hat , i=1in den Funktionsparametern. Damit soll vermieden werden, dass in ints konvertiert werden muss . Das .1ist, um Ungenauigkeiten zu behandeln; Ich denke, es ist sicher gegen Endlosschleifen.
26.
@xnor Ich habe den ersten Tipp erstmal umgesetzt. Ich überprüfe immer noch die Richtigkeit des zweiten, aber wenn es gut ist, sind das viele Bytes, die gespeichert wurden! (Außerdem habe ich eigentlich erwartet, dass du eine Lösung
postest
1
Und mit Njetzt einem Funktionsargument ist es kürzer, mit zu rekursieren N-1und zu prüfen, wann N==0und nicht len(n)==N.
29.
@ Sp3000 Ich bin jetzt überzeugt, dass das .1sicher ist; Wenn Sie möchten, kann ich Sie über ein Argument unterhalten.
Xnor
6

ECLiPSe-Prolog - 118 (138-20)

Ich habe die folgende Implementierung von Prolog verwendet: http://eclipseclp.org/

:-lib(util).
t(0,S,[]):-!,S<0.00001,S> -0.00001.
t(N,S,[X|Y]):-A is integer(ceiling(S*S)),between(1,A,X),M is N-1,T is S-sqrt(X),t(M,T,Y).

Dies ist ein sehr naiver, exponentieller Ansatz. Das Auflisten aller möglichen Lösungen nimmt Zeit in Anspruch, um alle Kombinationen abzudecken ( einige Bearbeiten : Der Bereich der besuchten Ganzzahlen nimmt jetzt mit jedem Schritt ab, wodurch viele unnötige Kombinationen entfernt werden).

Hier folgt ein Protokoll einer Testsitzung. Standardmäßig versucht die Umgebung, alle möglichen Lösungen zu finden (-10) und gibt "Nein" aus, wenn dies nicht der Fall ist (-10).

Wie Sp3000 im Kommentar richtig vermerkt hat, wird bei Erfolg auch "Ja" ausgegeben. Das bedeutet sicherlich, dass ich 10 weitere Punkte entfernen kann ;-)

[eclipse 19]: t(1,0.5,R).

No (0.00s cpu)
[eclipse 20]: t(2,3.414213562373095,R).

R = [2, 4]
Yes (0.00s cpu, solution 1, maybe more) ? ;

R = [4, 2]
Yes (0.00s cpu, solution 2, maybe more) ? ;

No (0.01s cpu)
[eclipse 21]: t(3,7.923668178593959,R).

R = [6, 7, 8]
Yes (0.02s cpu, solution 1, maybe more) ? ;

R = [6, 8, 7]
Yes (0.02s cpu, solution 2, maybe more) ? ;

R = [7, 6, 8]
Yes (0.02s cpu, solution 3, maybe more) ? 
[eclipse 22]: t(5,5.0,R).

R = [1, 1, 1, 1, 1]
Yes (0.00s cpu, solution 1, maybe more) ? ;
^C

interruption: type a, b, c, e, or h for help : ? abort
Aborting execution ...
Abort
[eclipse 23]: t(5,13.0,R).

R = [1, 1, 1, 1, 81]
Yes (0.00s cpu, solution 1, maybe more) ? ;

R = [1, 1, 1, 4, 64]
Yes (0.00s cpu, solution 2, maybe more) ? ;

R = [1, 1, 1, 9, 49]
Yes (0.00s cpu, solution 3, maybe more) ?
[eclipse 24]:

(Bearbeiten) In Bezug auf die Leistung ist es zumindest im Vergleich zu anderen recht gut (siehe zum Beispiel diesen Kommentar von FryAmTheEggman ). Fügen Sie zunächst das folgende Prädikat hinzu, wenn Sie alle Ergebnisse drucken möchten:

    p(N,S):-t(N,S,L),write(L),fail.
    p(_,_).

Unter http://pastebin.com/ugjfEHpw finden Sie den Fall (5,13.0), der in 0,24 Sekunden abgeschlossen ist und 495 Lösungen enthält (aber möglicherweise fehlen mir einige Lösungen, die ich nicht kenne).

Core-Dump
quelle
3
Es wird auch "Ja" gedruckt, wenn es erfolgreich ist! Oh Prolog.
Sp3000
3

Erlang, 305-10 302-10

f(M,D)->E=round(D*D),t(p(E,M,1),{M,E,D}).
p(_,0,A)->A;p(E,N,A)->p(E,N-1,A*E).
t(-1,_)->"No";t(I,{N,E,D}=T)->L=q(I,N,E,[]),V=lists:sum([math:sqrt(M)||M<-L])-D,if V*V<0.1e-9->lists:flatten([integer_to_list(J)++" "||J<-L]);true->t(I-1,T)end.
q(I,1,_,A)->[I+1|A];q(I,N,E,A)->q(I div E,N-1,E,[I rem E+1|A]).

Diese Funktion gibt die Zeichenfolge "Nein" oder eine Zeichenfolge mit durch Leerzeichen getrennten Werten zurück. Es verarbeitet (ineffizient) alle möglichen Werte, um sie in eine große Ganzzahl umzuwandeln, und beginnt mit höheren Werten. 0 sind in der Lösung nicht zulässig, und 0 steht für alle Einsen. Der Fehler ist quadriert.

Beispiel:

f(1,0.5).               % returns "No"
f(2,3.414213562373095). % returns "4 2 "
f(3,7.923668178593959). % returns "8 7 6 "
f(5,5.0).               % returns "1 1 1 1 1 "
f(5,13.0).              % returns "81 1 1 1 1 "

Bitte haben Sie etwas Geduld, f(5,13.0)da der Funktionssuchbereich 13 ^ 10 ist. Es kann mit 2 zusätzlichen Bytes schneller gemacht werden.

Paul Guyot
quelle
3

Python 3 2: 173 159 - 10 = 149

Erläuterung: Jede Lösung hat die Form x_1 x_2 ... x_n mit 1 <= x_1 <= x ^ 2, wobei x die Zielsumme ist. Daher können wir jede Lösung als ganze Zahl in der Basis x ^ 2 kodieren. Die while-Schleife durchläuft alle (x ^ 2) ^ n Möglichkeiten. Dann konvertiere ich die ganze Zahl zurück und teste die Summe. Ziemlich einfach.

i=input;n=int(i());x=float(i());m=int(x*x);a=m**n
while a:
 s=[a/m**b%m+1for b in range(n)];a-=1
 if abs(x-sum(b**.5for b in s))<1e-5:print' '.join(map(str,s))

Es werden alle Lösungen gefunden, aber der letzte Testfall dauert viel zu lange.

Jakube
quelle
3

JavaScript (ES6) 162 (172 - 10) 173

Bearbeiten Ein bisschen kürzer, ein bisschen langsamer.

Als eine Funktion mit 2 Parametern, Ausgabe auf Javascript-Konsole. Dies druckt alle Lösungen ohne Wiederholungen (Lösungstupel werden bereits sortiert generiert).
Es ging mir mehr um das Timing als um die Anzahl der Zeichen, sodass es in einer Browserkonsole innerhalb des Standard-JavaScript-Zeitlimits problemlos getestet werden kann.

(Update Februar 2016) Aktuelle Zeit für den letzten Testfall: ca. 1 150 Sek . Speicherbedarf: vernachlässigbar.

F=(k,t,z=t- --k,r=[])=>{
  for(r[k]=z=z*z|0;r[k];)
  { 
    for(;k;)r[--k]=z;
    for(w=t,j=0;r[j];)w-=Math.sqrt(r[j++]);
    w*w<1e-12&&console.log(r.join(' '));
    for(--r[k];r[k]<1;)z=--r[++k];
  }
}

ES 5 Version Beliebiger Browser

function F(k,t)
{
  var z=t- --k,r=[];  
  for(r[k]=z=z*z|0;r[k];)
  {
    for(;k;)r[--k]=z;
    for(w=t,j=0;r[j];)w-=Math.sqrt(r[j++]);
    w*w<1e-12&&console.log(r.join(' '));
    for(--r[k];r[k]<1;)z=--r[++k];
  }
}

Test Snippet sollte auf jedem aktuellen Browser ausgeführt werden

F=(k,t)=>
{
   z=t- --k,r=[];
   for(r[k]=z=z*z|0;r[k];)
   { 
      for(;k;)r[--k]=z;
      for(w=t,j=0;r[j];)w-=Math.sqrt(r[j++]);
      w*w<1e-12&&console.log(r.join(' '));
      for(--r[k];r[k]<1;)z=--r[++k];
   }
}

console.log=x=>O.textContent+=x+'\n'

t=~new Date
console.log('\n2, 3.414213562373095')
F(2, 3.414213562373095)
console.log('\n5, 5')
F(5, 5)
console.log('\n3, 7.923668178593959')
F(3, 7.923668178593959)
console.log('\n5, 13')
F(5, 13)

t-=~new Date
O.textContent = 'Total time (ms) '+t+ '\n'+O.textContent
<pre id=O></pre>

( Bearbeiten ) Unten sehen Sie das Ergebnis auf meinem PC, als ich diese Antwort vor 15 Monaten gepostet habe. Ich habe es heute versucht und es ist 100-mal schneller auf demselben PC, nur mit einer 64-Bit-Alpha-Version von Firefox (und Chrome hinkt deutlich hinterher)! - aktuelle Zeit mit Firefox 40 Alpha 64 Bit: ~ 2 Sek., Chrome 48: ~ 29 Sek

Ausgabe (auf meinem PC - letzte Nummer ist Laufzeit in Millisekunden)

2 4
1 1 1 1 1
6 7 8
1 1 1 1 81
1 1 1 4 64
1 1 1 9 49
1 1 4 4 49
1 1 1 16 36
1 1 4 9 36
1 4 4 4 36
1 1 1 25 25
1 1 4 16 25
1 1 9 9 25
1 4 4 9 25
4 4 4 4 25
1 1 9 16 16
1 4 4 16 16
1 4 9 9 16
4 4 4 9 16
1 9 9 9 9
4 4 9 9 9
281889
edc65
quelle
2

Mathematica - 76 - 20 = 56

f[n_,x_]:=Select[Union[Sort/@Range[x^2]~Tuples~{n}],Abs[Plus@@√#-x]<10^-12&]

Beispiele

f[2, 3.414213562373095]
> {{2, 4}}
f[3, 7.923668178593959]
> {{6, 7, 8}}
f[3, 12]
> {{1, 1, 100}, {1, 4, 81}, {1, 9, 64}, {1, 16, 49}, {1, 25, 36}, {4, 4, 64}, {4, 9, 49}, {4, 16, 36}, {4, 25, 25}, {9, 9, 36}, {9, 16, 25}, {16, 16, 16}}
swish
quelle
Wie wird das gedruckt No? Außerdem ist die Ausgabe nicht durch Leerzeichen getrennt. Kannst du auch nicht Tr@anstelle von verwenden Plus@@? Und Sie könnten in der Lage sein , einige Zeichen zu speichern , indem Sie Selectauf Cases, die Funktion am Ende zu einem Muster, und machte feine unbenannte reine Funktion.
Martin Ender
2

Haskell, 87 80 - 10 = 70

Dies ist ein rekursiver Algorithmus, der dem Python 3-Programm von @ Sp3000 ähnelt. Es besteht aus einer Infix-Funktion #, die eine Liste aller Permutationen aller Lösungen zurückgibt.

0#n=[[]|n^2<0.1^12]
m#n=[k:v|k<-[1..round$n^2],v<-(m-1)#(n-fromInteger k**0.5)]

Mit einer Punktzahl von 102 99 92 - 10 = 82 können wir jede Lösung nur einmal ausdrucken, sortiert:

0#n=[[]|n^2<0.1^12]
m#n=[k:v|k<-[1..round$n^2],v<-(m-1)#(n-fromInteger k**0.5),m<2||[k]<=v]
Zgarb
quelle
2

Pyth 55 54 47-20 = 27

DgGHKf<^-Hsm^d.5T2^10_12^r1hh*HHGR?jbmjdkKK"No

Probieren Sie es online aus.

Schamlos leiht sich von xnor Kommentar ;)

Dies führt auf jedem vernünftigen Computer sogar für einen Wert wie zu wenig Arbeitsspeicher 5,5.0. Definiert eine Funktion, gdie wie folgt aufgerufen werden kann g 3 7.923668178593959.

Dieses Python 3-Programm verwendet im Wesentlichen den gleichen Algorithmus (führt am Ende nur nicht den "Nein" print(K if K else "No")-Druck aus, was durch Zuweisen einer Variablen zu allen Ergebnissen und anschließendes Schreiben erfolgen kann ), sondern verwendet einen Generator. Es wird kein Speicherfehler angezeigt (es dauert immer noch sehr lange, aber ich habe den Ausdruck so eingestellt, dass die Werte gefunden werden):

Dies ergab genau die gleichen Ergebnisse wie bei @ Sp3000. Es dauerte auch einige Tage, bis ich fertig war (ich hatte keine Zeit dafür, aber ungefähr 72 Stunden).

from itertools import*
def g(G,H):
    for x in product(range(1,int(H*H+2)),repeat=G):
        if (H-sum(map(lambda n:n**.5,x)))**2<1e-12:print(*x)
FryAmTheEggman
quelle
1

Python 3 - 157 174 169 - 10 = 159

Edit1: Das Ausgabeformat wurde in durch Leerzeichen getrennte Ganzzahlen anstatt durch Kommas getrennt geändert. Vielen Dank für den Tipp, die Klammern um (n, x) zu entfernen.

Edit2: Danke für die Golftipps! Ich kann weitere 9 Zeichen abschneiden, wenn ich nur einen == Test verwende, anstatt die ungefähre Gleichheit innerhalb von 1e-6 zu testen, aber das würde ungefähre Lösungen, falls solche existieren, ungültig machen.

Verwendet itertools, um alle möglichen Ganzzahlkombinationen zu generieren, hoffentlich effizient :)

Ich habe keine Möglichkeit gefunden, effizient "Nein" zu drucken. Es sind immer mehr als 10 zusätzliche Zeichen erforderlich.

from itertools import*
n,x=eval(input())
for c in combinations_with_replacement(range(1,int(x*x)),n):
 if abs(sum(z**.5for z in c)-x)<1e-6:print(' '.join(map(str,c)))
RT
quelle
Ihr Programm hat das falsche Ausgabeformat (Kommas statt Leerzeichen). Sie können auch 2 Bytes sparen, indem Sie die Klammern entfernen n,x.
Zgarb
Ich scheine SyntaxErrors zu bekommen, wenn ich die evalLinie versuchen ...
Sp3000
@ Sp3000: Versuchen Sie, 3,7.923668178593959 einzugeben. Du brauchst das ','
Jakube
4 kleine Verbesserungen: from itertools import*Speichert 1, entfernt den Platz z**.5forspart 1 und entfernt den []In- sum(z**.5for z in c)Speicher 2 und entfernt den ()In- if(...)Speicher 1.
Jakube
Wäre eine Umstellung auf Python 2 und die Verwendung n,x=input()kompakter?
Octavia Togami
0

Scala (397 Bytes - 10)

import java.util.Scanner
object Z extends App{type S=Map[Int,Int]
def a(m:S,i:Int)=m updated(i,1+m.getOrElse(i,0))
def f(n:Int,x:Double):Set[S]={if(n==0){if(x.abs<1e-6)Set(Map())else Set()}
else((1 to(x*x+1).toInt)flatMap{(i:Int)=>f(n-1,x-Math.sqrt(i))map{(m:S)=>a(m,i)}}).toSet}
val s=new Scanner(System.in)
f(s.nextInt,s.nextDouble)foreach{(m:S)=>m foreach{case(k,v)=>print(s"$k "*v)};println}}

Wenn es keine Permutationen gibt, druckt dieses Programm nichts.

bb94
quelle