Taglia la catena d'oro


32

Un viaggiatore deve rimanere per n giorni in un hotel fuori città. Ha esaurito i contanti e la sua carta di credito è scaduta. Ma ha una catena d'oro con n collegamenti.

La regola in questo hotel è che i residenti dovrebbero pagare l'affitto ogni mattina. Il viaggiatore raggiunge un accordo con il gestore per pagare un anello della catena d'oro per ogni giorno. Ma il manager richiede anche che il viaggiatore debba fare il minimo danno possibile alla catena mentre paga ogni giorno. In altre parole, deve trovare una soluzione per tagliare il minor numero possibile di collegamenti.

Il taglio di un collegamento crea tre subchain: uno contenente solo il collegamento tagliato e uno su ciascun lato. Ad esempio, il taglio del terzo anello di una catena di lunghezza 8 crea delle catene secondarie di lunghezza [2, 1, 5]. Il gestore è felice di apportare modifiche, in modo che il viaggiatore possa pagare il primo giorno con la catena di lunghezza 1, quindi il secondo giorno con la catena di lunghezza 2, riprendendo la prima catena.

Il tuo codice dovrebbe inserire la lunghezza n e produrre un elenco di collegamenti da tagliare di lunghezza minima.

Regole :

  • n è un numero intero> 0.
  • È possibile utilizzare l'indicizzazione basata su 0 o 1 per i collegamenti.
  • Per alcuni numeri, la soluzione non è unica. Ad esempio, se n = 15entrambi [3, 8]e [4, 8]sono output validi.
  • È possibile restituire l'elenco o stamparlo con qualsiasi separatore ragionevole.
  • Questo è , quindi vince il codice più breve in byte.

Casi di prova :

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

Esempio dettagliato

Per n = 15, tagliando i collegamenti 3 e 8 si ottengono subchain di lunghezza [2, 1, 4, 1, 7]. Questa è una soluzione valida perché:

 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

Non esiste una soluzione con un solo taglio, quindi questa è una soluzione ottimale.

appendice

Si noti che questo problema è correlato al partizionamento intero. Stiamo cercando una partizione P di n tale che tutti i numeri interi da 1 a n abbiano almeno una patizione che è un sottoinsieme di P .

Ecco un video di YouTube su un possibile algoritmo per questo problema.


Non capisco il tuo riferimento "apportare modifiche". Nell'esempio pubblicato, il secondo giorno paghi con la catena a 2 maglie (e ottieni la catena a 1 maglie (che hai pagato con il giorno prima) come cambio, secondo la tua spiegazione). Ma il terzo giorno, paghi con 1+2. Da dove viene la seconda catena a 2 maglie?
Flater,

4
@Flater Il gestore ce l'ha già. Paghiamo solo quello aggiuntivo. In effetti, l'RHS sono i link che il gestore possiede ogni giorno
polfosol ఠ_ఠ

Risposte:


15

05AB1E , 23 11 8 byte

ΔÍN-;иg=

Provalo online!

Utilizza l'indicizzazione basata su 0.

Spiegazione:

             # 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

иgsembra un noop, ma in realtà fa due cose utili: si tronca a un numero intero ( ;restituisce un float) e si arresta in modo anomalo all'interprete se x è negativo (questa è l'unica condizione di uscita).


La soluzione a 23 byte utilizzava un approccio molto diverso, quindi eccola per i posteri: ÅœʒR2äθP}ʒæOê¥P}θ2äθη€O( TIO , spiegazione ).


2
Ho cancellato la mia risposta. Il mio essere 42 e il tuo essere 11 è una differenza troppo grande per me per non sentirmi in imbarazzo, ahah. ;) Bella risposta però, e lol al Ø.Ø. Hai appena provato alcune cose casuali al fine di mappare e mappare tutti i negativi -1? Indipendentemente da ciò, bella risposta e molto più breve di quanto mi aspettassi. Stavo pensando a circa 20 byte dopo aver pubblicato il mio cattivo 42-byte.
Kevin Cruijssen il

2
@KevinCruijssen Nnope, in Ø.Ørealtà è stata la mia prima idea. Il tuo commento mi ha ispirato a provare cose a caso: ho trovato ®Ÿà, ï®Me cosa ancora più importante, иgche le rese questo bel 8-byter. Ho sempre trovato fastidioso il fatto che osabie preferisca non fare nulla rispetto agli arresti anomali in molti casi (div per 0, tipo sbagliato, ecc.), Quindi questo arresto sarà utile.
Grimmy,

2
Hehe, 05AB1E non dovrebbe mai andare in crash, ma hai ragione che a volte è un po 'fastidioso che non lo fa mai. Nell'eredità non sapevo nemmeno come andare in crash, e in passato avevamo persino una divisione esplicita per zero errori che potremmo chiamare manualmente. xD Nella nuova versione si blocca ancora abbastanza spesso con un errore quando si danno argomenti errati a determinati builtin. E bello di nuovo -3.
Kevin Cruijssen il

2
"blocca l'interprete se x è negativo (questa è l'unica condizione di uscita)." - Lo adoro
John Dvorak il

9

Python 2 , 75 byte

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)]

Provalo online!


Spiegazione:

Crea una sequenza di blocchi "binari", con un numero di base corrispondente al numero di tagli.

Per esempio:

63 può essere fatto in 3 tagli, il che significa una partizione in base-4 (dato che abbiamo 3 anelli singoli):

tagli: 5, 14, 31 che dà catene di 4 1 8 1 16 1 32(ordinati:) 1 1 1 4 8 16 32.

Tutti i numeri possono essere fatti:

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

Altri esempi:

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
Non dovresti aggiungere f=all'inizio? Dato che usi una chiamata fnella funzione lambda e posso solo supporre che ti riferisci alla stessa lambda che stai definendo.
randomdude999,

@ randomdude999, Sì, ho dimenticato ...
TFeld il

@ randomdude999 questa regola si applica a tutte le lingue o solo a Python? Perché vedo una risposta javascript che è una pura lambda in questa sfida ...
Shadow

3
@Shadow Si applica a tutte le lingue, ma solo per lambda ricorsive.
TFeld il

1
@Shadow Una regola più generica è che non puoi fare riferimento a qualcosa che non è né definito nel tuo codice né globalmente definito nella tua lingua, a meno che non sia esplicitamente consentito dalla sfida. Il caso più comune è una funzione ricorsiva, ma questo vale per altre situazioni. Questa risposta è un altro esempio: fnon è ricorsivo, ma è comunque referenziato nel codice e quindi deve essere nominato.
Arnauld, il

8

R , 77 69 byte

-8 byte grazie ad Aaron Hayman

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

Provalo online!

KK(K+1)2Kn1,1,...,1K(K+1),2(K+1),4(K+1),8(K+1),...,(K+1)2K-1

(Potrebbe essere necessario abbreviare l'ultimo sottochain se superiamo la lunghezza totale della catena.)

Ungolfed (basato su una versione precedente e simile):

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.)

un'(K)n richiedendo K tagli, quindi un'(K)è OEIS A134401 .


Dubito che aiuterebbe con il caso speciale per n=1, ma un modo alternativo per generare i tagli è la ricorrenza 1, 4, 4a(n-1)-4a(n-2).
Peter Taylor,

@PeterTaylor Ho avuto una ricorrenza simile per l'informatica k; questo corrisponde a OEIS A134401: oeis.org/A134401 Ma la mia implementazione della relazione di ricorrenza occupa più byte del codice corrente.
Robin Ryder il

Un po 'di riarrangiamento l'ho portato a 73. Provalo online!
Aaron Hayman,

@AaronHayman Grazie! Mossa intelligente usando suminvece di match.
Robin Ryder il

69 byte e mi sono sbarazzato di quell'affermazione che ti ha sconvolto: provalo online!
Aaron Hayman il



2

C ++, 109 , 107 byte

-2 byte grazie a 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<<',';}

L'algoritmo è simile alla risposta di Robin Ryder. Il codice è scritto in una forma completa e compilabile. Provalo!

Dettagli:

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

Questo ha una variazione C con la stessa lunghezza di byte (non sembra aver bisogno di una risposta separata):

#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);}

Due cose minori da golf: =0dopo kpuò essere rimosso, dal momento che è 0di default. std::cin>>n;while(++k<<k<n);può essere for(std::cin>>n;++k<<k<n;);. Ho anche la sensazione che for(n-=k;n>0;k*=2,n-=k+1)possa essere semplificato in qualche modo combinando cose, ma non sono sicuro di come. PS: Cambiare il delimitatore virgola in uno spazio sembra leggermente migliore dal momento che non vedi il trailing uno imo, ma questo è puramente cosmetico :)
Kevin Cruijssen

1
@KevinCruijssen Grazie, ma alcuni compilatori non assegnano un valore predefinito a variabili non statiche. Quindi ho pensato che =0fosse necessario per la portabilità;) Ho anche capito che lo spazio dopo #includenon è necessario.
polfosol ఠ_ఠ

Ah ok. Non conosco troppo bene il C ++, quindi ho usato quel compilatore online che hai collegato nella tua risposta per testare alcune cose. :) Hai dimenticato la seconda modifica che ho proposto nel mio commento: il while-loop in un for-loop e mettendoci std::cin>>ndentro.
Kevin Cruijssen,


1

Retina 0.8.2 , 61 byte

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

Provalo online! 1 porta indicizzata della risposta di @Grimy. Spiegazione:

.+
11,$&$*

Inizia con N=2e l'input convertito in unario.

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

Cerca ripetutamente di sottrarre Ndall'input e poi dividi per 2.

1$2¶1$1,$3

In caso di successo, ricordare 1 in più rispetto all'input sulla riga precedente, incrementare Nsulla riga corrente e aggiornare l'input con il nuovo valore.

1+,
1

Rimuovi Ne incrementa l'ultimo valore in modo che sia anche 1-indicizzato.

1A`

Rimuovere l'input originale incrementato.

1+
$.&

Converti i risultati in decimale.


1

Rubino , 62 byte

->n{(1...c=(0..n).find{|r|n<r<<r}).map{|b|[n,b-c+(c<<b)].min}}

Provalo online!

Per lo più rubato dalla risposta Python di TFeld.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.