Schneiden Sie die Goldkette


32

Ein Reisender muss n Tage in einem Hotel außerhalb der Stadt bleiben . Er hat kein Geld mehr und seine Kreditkarte ist abgelaufen. Aber er hat eine goldene Kette mit n Gliedern.

Die Regel in diesem Hotel ist, dass die Bewohner ihre Miete jeden Morgen bezahlen sollten. Der Reisende vereinbart mit dem Manager, dass er für jeden Tag ein Glied der goldenen Kette zahlt. Der Manager fordert aber auch, dass der Reisende die Kette so wenig wie möglich beschädigt, während er jeden Tag zahlt. Mit anderen Worten, er muss eine Lösung finden, um so wenig Glieder wie möglich zu schneiden.

Durch das Ausschneiden einer Verknüpfung werden drei Unterketten erstellt: eine, die nur die ausgeschnittene Verknüpfung enthält, und eine auf jeder Seite. Wenn Sie beispielsweise das dritte Glied einer Kette mit der Länge 8 abschneiden, werden Unterketten mit der Länge [2, 1, 5] erstellt. Der Manager nimmt gerne Änderungen vor, sodass der Reisende den ersten Tag mit der Kette der Länge 1 und den zweiten Tag mit der Kette der Länge 2 bezahlen und die erste Kette zurückerhalten kann.

Ihr Code sollte die Länge n eingeben und eine Liste der zu schneidenden Links mit minimaler Länge ausgeben.

Regeln :

  • n ist eine ganze Zahl> 0.
  • Sie können für die Links entweder eine 0-basierte oder eine 1-basierte Indizierung verwenden.
  • Für einige Zahlen ist die Lösung nicht eindeutig. Zum Beispiel, wenn n = 15beide [3, 8]und [4, 8]gültige Ausgaben sind.
  • Sie können die Liste entweder zurückgeben oder mit einem geeigneten Trennzeichen drucken.
  • Das ist , also gewinnt der kürzeste Code in Bytes.

Testfälle :

Input          Output (1-indexed)
1              []
3              [1]
7              [3]
15             [3, 8]
149            [6, 17, 38, 79]

Ausführliches Beispiel

Für n = 15 führt das Schneiden der Glieder 3 und 8 zu Unterketten mit einer Länge [2, 1, 4, 1, 7]. Dies ist eine gültige Lösung, weil:

 1 = 1
 2 = 2
 3 = 1+2
 4 = 4
 5 = 1+4
 6 = 2+4
 7 = 7
 8 = 1+7
 9 = 2+7
10 = 1+2+7
11 = 4+7
12 = 1+4+7
13 = 2+4+7
14 = 1+2+4+7
15 = 1+1+2+4+7

Es gibt keine Lösung mit nur einem Schnitt, daher ist dies eine optimale Lösung.

Nachtrag

Beachten Sie, dass dieses Problem mit der Partitionierung ganzer Zahlen zusammenhängt. Wir suchen nach einer Partition P von n, so dass alle ganzen Zahlen von 1 bis n mindestens eine Partition haben, die eine Teilmenge von P ist .

Hier ist ein YouTube-Video zu einem möglichen Algorithmus für dieses Problem.


Ich verstehe Ihren Hinweis auf "Änderungen vornehmen" nicht. In Ihrem geposteten Beispiel zahlen Sie am zweiten Tag mit der 2-Gliederkette (und erhalten die 1-Gliederkette (die Sie am Vortag bezahlt haben) gemäß Ihrer Erklärung als Wechselgeld zurück). Aber am dritten Tag zahlen Sie mit 1+2. Woher kommt die zweite 2-Gliederkette?
Flater

4
@Flater Der Manager hat es bereits. Wir zahlen nur die zusätzliche. In der Tat sind die RHS die Links, die Manager jeden Tag besitzt
Polfosol ఠ_ఠ

Antworten:


15

05AB1E , 23 11 8 Bytes

ΔÍN-;иg=

Probieren Sie es online!

Verwendet eine 0-basierte Indizierung.

Erläuterung:

             # start from the implicit input
Δ            # loop forever
 Í           # subtract 2
  N-         # subtract the current iteration number
    ;        # divide by 2
     и       # create a list of length x
      g      # get the length of the list
       =     # print

иgEs sieht aus wie ein Noop, macht aber zwei nützliche Dinge: Es schneidet auf eine Ganzzahl ab ( ;gibt einen Float zurück) und stürzt den Interpreter ab, wenn x negativ ist (dies ist die einzige Exit-Bedingung).


Die 23-Byte-Lösung verwendete einen ganz anderen Ansatz, und hier ist es für die Nachwelt: ÅœʒR2äθP}ʒæOê¥P}θ2äθη€O( TIO , Erklärung ).


2
Ich habe meine Antwort gelöscht. Meines ist zu groß, als dass ich 42 und deines ist, als dass ich mich nicht schäme, haha. ;) Nette Antwort, und lol bei der Ø.Ø. Haben Sie nur ein paar zufällige Dinge ausprobiert, um sowohl Stockwerke als auch alle Negative zuzuordnen -1? Egal, sehr nette Antwort und viel kürzer als ich erwartet hatte. Ich habe ungefähr 20 Bytes nachgedacht, nachdem ich meine schlechten 42 Bytes gepostet habe.
Kevin Cruijssen

2
@ KevinCruijssen Nnope, Ø.Øwar eigentlich meine erste Idee. Ihr Kommentar hat mich dazu inspiriert, zufällige Dinge auszuprobieren: Ich habe festgestellt ®Ÿà, ï®Mund was noch wichtiger ist иg, dass dies ein schöner 8-Byte-Wert ist. Ich fand es immer ärgerlich, dass osabie es in vielen Fällen vorzieht, nichts zu tun, anstatt abzustürzen (dividiert durch 0, falscher Typ usw.), so dass dieser Absturz nützlich sein wird.
Grimmy

2
Hehe, 05AB1E soll niemals abstürzen, aber Sie haben Recht, dass es manchmal etwas nervig ist, was es niemals tut. Im Erbe wusste ich nicht einmal, wie man abstürzt, und in der Vergangenheit hatten wir sogar eine explizite Trennung durch Null Fehler könnten wir manuell aufrufen. xD In der neuen Version stürzt es immer noch häufig mit einem Fehler ab, wenn bestimmte integrierte Funktionen mit falschen Argumenten versehen werden. Und wieder schön -3.
Kevin Cruijssen

2
msgstr "stürzt der Interpreter ab, wenn x negativ ist (dies ist die einzige Ausgangsbedingung)." - Ich liebe das
John Dvorak

9

Python 2 , 75 Bytes

f=lambda n,i=0:n>=i<<i and f(n,i+1)or[min(n,2**j*i-i+j)for j in range(1,i)]

Probieren Sie es online!


Erläuterung:

Bildet eine Folge von 'binären' Blöcken, wobei eine Basisnummer mit der Anzahl der Schnitte übereinstimmt.

Z.B:

63 kann in 3 Schnitten gemacht werden, was eine Partition in Basis 4 bedeutet (da wir 3 einzelne Ringe haben):

Cuts:, 5, 14, 31was Ketten von 4 1 8 1 16 1 32(sortiert :) ergibt 1 1 1 4 8 16 32.

Alle Zahlen können gemacht werden:

1       1
2       1 1
3       1 1 1
4       4
...
42      1 1 8 32
...
62      1 1 4 8 16 32
63      1 1 1 4 8 16 32

Andere Beispiele:

18: 4,11        ->  3 1 6 1 7
27: 5,14,27     ->  4 1 8 1 13 1
36: 5,14,31     ->  4 1 8 1 16 1 5
86: 6,17,38,79  ->  5 1 10 1 20 1 40 1 7

1
Sollten Sie nicht f=zum Start hinzufügen ? Da Sie fin der Lambda-Funktion einen Aufruf von verwenden, kann ich nur davon ausgehen, dass Sie sich auf dasselbe Lambda beziehen, das Sie definieren.
randomdude999

@ randomdude999, Ja, ich habe vergessen ...
TFeld

@ randomdude999 Gilt diese Regel für alle Sprachen oder nur für Python? Weil ich eine Javascript-Antwort sehe, die in dieser Herausforderung ein reines Lambda ist ...
Schatten

3
@Shadow Gilt für alle Sprachen, jedoch nur für rekursive Lambdas.
TFeld

1
@Shadow Eine allgemeinere Regel ist, dass Sie nicht auf etwas verweisen können, das weder in Ihrem Code definiert ist noch global in Ihrer Sprache definiert ist, es sei denn, die Challenge lässt dies ausdrücklich zu. Der häufigste Fall ist eine rekursive Funktion, dies gilt jedoch auch für andere Situationen. Diese Antwort ist ein weiteres Beispiel: Sie fist nicht rekursiv, wird jedoch im Code referenziert und muss daher benannt werden.
Arnauld

8

R , 77 69 Bytes

-8 Bytes dank Aaron Hayman

pmin(n<-scan(),0:(k=sum((a=2:n)*2^a<=n))+cumsum((k+2)*2^(0:k))+1)[-n]

Probieren Sie es online!

kk(k+1)2kn1,1,,1k(k+1),2(k+1),4(k+1),8(k+1),,(k+1)2k-1

(Die letzte Unterkette muss möglicherweise gekürzt werden, wenn die Gesamtlänge der Kette überschritten wird.)

Ungolfed (basierend auf einer früheren, ähnlichen Version):

n = scan()                            # read input
if(n - 1){                            # If n==1, return NULL
  k = match(F, (a = 2:n) * 2 ^ a > n) # compute k
  b = (k + 1) * 2 ^ (1:k - 1)         # lengths of subchains
  c = 1:k + cumsum(b)                 # positions of cuts
  pmin(c, n )                         # if last value is >n, coerce it to n
}

kkkk+12k+12k+24k+4k(k+1)2k-1.)

ein(k)nkein(k)


Ich bezweifle, dass dies für den Sonderfall hilfreich wäre n=1, aber eine alternative Möglichkeit, die Grenzwerte zu generieren, ist die Wiederholung 1, 4, 4a(n-1)-4a(n-2).
Peter Taylor

@ PeterTaylor Ich hatte eine ähnliche Wiederholung für das Rechnen k; dies entspricht OEIS A134401: oeis.org/A134401 Meine Implementierung der Wiederholungsrelation benötigt jedoch mehr Bytes als der aktuelle Code.
Robin Ryder

Ein bisschen Neuordnung habe ich es auf 73 gebracht. Online ausprobieren!
Aaron Hayman

@ AaronHayman Danke! Smart Move mitsum statt match.
Robin Ryder

69 Bytes und haben die if-Anweisung entfernt, die Sie störte: Probieren Sie es online aus!
Aaron Hayman



2

C ++, 109 , 107 Bytes

-2 Bytes dank Kevin

#include<iostream>
main(){int n,k=0;for(std::cin>>n;++k<<k<n;);for(n-=k;n>0;k*=2,n-=k+1)std::cout<<n<<',';}

Der Algorithmus ähnelt der Antwort von Robin Ryder. Der Code ist in einer kompilierbaren, vollständigen Form geschrieben. Versuch es!

Einzelheiten:

std::cin>>n;               // get the value of n as input
while(++k<<k<n);           // determine k
for(n-=k;n>0;k*=2,n-=k+1)  // we don't need n, so the lengths...
    std::cout<<n<<' ';     // of links are subtracted repeatedly

Dies hat eine C- Variante mit der gleichen Bytelänge (scheint keine separate Antwort zu benötigen):

#include<stdio.h>
main(){int n,k=0;for(scanf("%d",&n);++k<<k<n;);for(n-=k;n>0;k*=2,n-=k+1)printf("%d,",n);}

Zwei Kleinigkeiten zum Golfen: =0After kkann entfernt werden, da es 0standardmäßig ist. std::cin>>n;while(++k<<k<n);kann sein for(std::cin>>n;++k<<k<n;);. Ich habe auch das Gefühl, man for(n-=k;n>0;k*=2,n-=k+1)kann es irgendwie vereinfachen, indem man Sachen kombiniert, aber ich weiß nicht wie. PS: Das Ändern des Komma-Trennzeichens in ein Leerzeichen sieht etwas besser aus, da Sie das nachgestellte imo nicht sehen, aber das ist rein kosmetisch :)
Kevin Cruijssen

1
@KevinCruijssen Vielen Dank, aber einige Compiler weisen nicht statischen Variablen keinen Standardwert zu. Also dachte ich =0war notwendig für die Portabilität;) Ich erkannte auch, dass der Raum danach #includenicht notwendig ist.
Polfosol ఠ_ఠ

Ach ok Ich kenne C ++ nicht so gut, also habe ich diesen Online-Compiler, den Sie in Ihrer Antwort verlinkt haben, verwendet, um einige Dinge zu testen. :) Du hast die zweite Änderung, die ich in meinem Kommentar vorgeschlagen habe, vergessen: die while-Schleife in eine for-Schleife und die std::cin>>ndarin enthaltene.
Kevin Cruijssen


1

Retina 0.8.2 , 61 Bytes

.+
11,$&$*
+`\b(1+),(\1(1*)1?\3)$
1$2¶1$1,$3
1+,
1
1A`
1+
$.&

Probieren Sie es online! 1-indizierter Port von @ Grimys Antwort. Erläuterung:

.+
11,$&$*

Beginnen Sie mit N=2und konvertieren Sie die Eingabe in Unary.

+`\b(1+),(\1(1*)1?\3)$

Versuchen Sie wiederholt, Nvon der Eingabe zu subtrahieren und dann durch 2 zu dividieren.

1$2¶1$1,$3

Wenn erfolgreich, merken Sie sich 1 mehr als die Eingabe in der vorherigen Zeile, erhöhen Sie Ndie Eingabe in der aktuellen Zeile und aktualisieren Sie die Eingabe auf den neuen Wert.

1+,
1

Entfernen Sie Nden letzten Wert und erhöhen Sie ihn, damit er auch 1-indiziert ist.

1A`

Entfernen Sie die inkrementierte Originaleingabe.

1+
$.&

Konvertieren Sie die Ergebnisse in Dezimalzahlen.


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.