Quanto tempo ci vuole per dipingere un bastone?


12

(Basato su questo problema Math.SE , che fornisce anche alcuni elementi grafici)

Ho un bastone che sembra un po 'così:

inserisci qui la descrizione dell'immagine

Voglio che sembri un po 'così:

inserisci qui la descrizione dell'immagine

Non sono un pittore esperto, tuttavia, quindi prima di iniziare un progetto fai-da-te così ambizioso, voglio assicurarmi di non essere sopra la testa.

Il tuo programma dovrebbe dirmi quanti passaggi sono necessari per dipingere questo bastone. Ogni passaggio prevede la verniciatura di un'area continua con un colore a tinta unita, che copre i precedenti strati di vernice. Per l'esempio sopra, ho potuto dipingere la metà blu a sinistra, la metà rossa a destra e quindi le due aree verdi separate per un totale di 4 passaggi (il verde non è continuamente dipinto).

inserisci qui la descrizione dell'immagine

Eccolo in ASCII:

------
bbb---
bbbrrr
bgbrrr
bgbrgr

Ci sono un paio di modi diversi per dipingere questo bastone e finire con lo stesso risultato. Sono interessato solo alla stima del tempo, tuttavia, che è di quattro passaggi.

Obbiettivo

Il programma dovrebbe generare il numero minimo di passaggi necessari per dipingere un bastone con una determinata combinazione di colori. Lo schema di disegno avrà la forma di una stringa di caratteri, mentre l'output sarà un numero. Questo è il codice golf. Vince il programma più breve.

Ingresso

Il tuo programma riceverà lo schema di colorazione per un bastone sotto forma di una stringa di lettere. Ogni lettera univoca (maiuscole e minuscole) rappresenta un colore unico.

YRYGR

grG

GyRyGyG

pbgbrgrp

hyghgy

Produzione

Questi numeri sono il numero minimo di passaggi necessari per dipingere i bastoncini.

4

3

4

5

4

spiegazioni

Ecco come sono arrivato ai numeri sopra. Il tuo programma non ha bisogno di produrre questo:

 -----
 YYY--
 YRY--
 YRYG-
 YRYGR

 ---
 g--
 gr-
 grG

 -------
 GGGGGGG
 GyyyGGG
 GyRyGGG
 GyRyGyG

 --------
 pppppppp
 pbbbpppp
 pbbbrrrp
 pbgbrrrp
 pbgbrgrp

 ------
 -yyyyy
 -ygggy
 hygggy
 hyghgy

Modifica: aggiungerò altri casi di test se si rivelano casi di test più difficili.


Questo mi ricorda stackoverflow.com/q/10364248/785745 , che è simile, ma in 2D.
Kendall Frey,

Risposte:


3

GolfScript, 82 72 67 caratteri

.,n*{:c,,{[).2$1<*\c>+1$.,,{).2$<\3$<=},,.@>@@>]}%\;{~S)}%$0+0=}:S~

Abbastanza veloce per un programma GolfScript, esempi:

> hyghgy
4

> pbgbrgrp
5

L'algoritmo utilizzato funziona in modo ricorsivo attraverso i colori da sinistra a destra, secondo le seguenti affermazioni:

  • Ignora tutte le parti da sinistra che hanno già il colore richiesto. Sovraverniciarli di nuovo non fornirà una risposta migliore.
  • Se lo stick completo ha già il colore desiderato, restituire 0 passaggi come risultato.
  • Altrimenti, prendi il colore target della parte ora più a sinistra (cioè il primo non nel colore desiderato).

    • Dipingi 1 parte con il colore target e ricorri.
    • Dipingi 2 parti con questo colore e ricomincia.

    ...

    • Dipingi l'intero bastoncino rimanente con questo colore e ricomincia.

    Prendi il minimo di tutti quei numeri e aggiungi 1 (per il passaggio corrente). Restituisci questo come il numero ottimale di passaggi.

Questo algoritmo funziona, perché la parte più a sinistra deve essere dipinta in una volta in ogni caso, quindi perché non farlo immediatamente - in ogni modo possibile.

.,n*         # prepare the initial situation (target stick, unpainted stick)
             # used n instead of '-' for the unpainted parts, because it is shorter
{            # Define the operator S which does t c S -> n
             #   - t: the desired target colors
             #   - c: the stick as it is colored currently
             #   - n: minimum number of steps required to go from c to t
  :c         # Assign the current configuration to the variable c
  ,,{[       # Map the list [0 1 2 .. L-1]
             # We will build a list of all possible configurations if we paint
             # the stick with the 0th part's color (either 1 or 2 or 3 or ... parts)
    ).       # Increase the number, i.e. we paint 1, 2, 3, ... L parts, copy
    2$1<     # Take the first color of the target configuration
    *        # ...paint as many parts
    \c>+     # ...and keep the rest as with the current stick
    1$       # take the target configuration
             # Top of stack now e.g. reads
             #    h----- hyghgy (for i=0)
             #    hh---- hyghgy (for i=1)
             # Next, we strip the common leading characters from both strings:
    .,,      # Make list [0 1 2 ... L-1]
    {        # Filter {}, all the numbers for which the first j+1 parts are the same
      ).     # incr j
      2$<    # take leftmost j parts of stick A
      \3$<   # take leftmost j parts of stick B
      =      # are they equal?
    },,      # The length of the result is the number of common parts.
    .@>      # cut parts from A
    @@>      # cut parts from B
  ]}%
  \;         # Remove the target from the stack (not needed anymore)               
             # We now have a list of possible paintings where 1, 2, ..., L parts were
             # painted from the left with the same color.
             # All configurations were reduced by the common parts (they won't be
             # painted over anyways)
  {~S)}%     # Call the method S recursively on the previously prepared configurations
  $0+0=      # $0= -> sort and take first, i.e. take the minimum, 0+ is a workaround
             # if the list was empty (i.e. the operator was called with a stick of length 0).
}:S
~            # Execute S

+1 per l'algoritmo "colore più a sinistra sbagliato". Tuttavia, sembra essere n!passi;) (ma forse questa è la vera complessità, non lo so).
yo

2

JavaScript: 187 byte

Supponendo che possiamo solo avere l'input e l'output di una funzione (per favore)!

function p(w){var j,l,s=-1,i,m=i=w.length;if(m<2)return m;for(;i--;){l = 1;for(var k=-1;(j=k)!=m;){if((k=w.indexOf(w[i],++j))==-1)k=m;l+=p(w.substring(j,k));}if(s==-1||l<s)s=l;}return s;}

157 byte facendo ulteriori brutte ottimizzazioni (che è parte del punto e ho trovato incredibilmente divertente):

function p(w){var j,l,s=-1,i,m=i=w.length;if(m<2)return m;for(;i--;s<0|l<s?s=l:1)for(l=1,j=0;~j;)l+=p(w.substring(j,(j=w.indexOf(w[i],j))<0?m:j++));return s}

135 byte Mi sono reso conto che la lunghezza dell'input è un limite superiore e non ho bisogno di gestire casi banali separatamente ora.

function p(w){var j,l,s,i,m=s=i=w.length;for(;i--;l<s?s=l:1)for(l=1,j=0;~j;)l+=p(w.substring(j,~(j=w.indexOf(w[i],j))?j++:m));return s}

Casi test:

p("YRYGR")
4
p("grG")
3
p("GyRyGyG")
4
p("pbgbrgrp")
5
p("hyghgy")
4

Versione estesa:

function paint(word) {
    var smallest = -1;
    if(word.length < 2) return word.length;
    for(var i = word.length; i-->0;) {
        var length = 1;
        for(var left, right = -1;(left = right) != m;) {
            if((right = word.indexOf(word[i],++left)) == -1) right = word.length;
            if(left != right) length += paint(word.substring(left , right));
        }
        if(smallest == -1 || length < smallest) smallest = l;
    }
    return smallest;
}

Per ogni carattere dell'input, calcola la lunghezza del motivo se dipingiamo prima quel colore. Questo viene fatto fingendo di dipingere quel colore e quindi ricavando sottosezioni dai bit che non sono quel colore e chiamando ricorsivamente il metodo di pittura su di essi. Viene restituito il percorso più breve.

Esempio ( YRYGR):

Inizialmente, prova R. Questo ci dà i sottogruppi Ye YG. Yè banalmente dipinto in una volta sola.

Per YG: provare G, Yè banale, lunghezza 2. Prova Y, Gè banale, lunghezza 2. YGè quindi lunghezza 2.

La pittura Rprima ci dà quindi1 + 1 + 2 = 4

Quindi prova G. Questo ci dà i sottogruppi YRYe R. Rè banale.

Per YRY:

Prova Y: Rè banale, lunghezza 2. Prova R: Ye Ysono i due gruppi, lunghezza 3.

YRYè lunghezza 2.

La pittura Gdapprima dà1 + 1 + 2 = 4

Quindi prova Y. Questo dà i sottogruppi Re GR. Rbanale, GRè lunghezza 2. Yè lunghezza4

Questa implementazione controlla quindi nuovamente R e Y per ridurre la lunghezza del codice. Il risultato YRYGRè quindi 4.


Penso che la tua versione estesa abbia perso la var mda qualche parte.
Hasturkun,

Sfortunatamente, anche la tua versione non fornisce il risultato corretto per l'input "abcacba".
Howard,

@Hasturkun mera solo una scorciatoia per word.length:) @Howard Hai ragione, dovrò ripensarci.
meiamsome

1

Python, 149 caratteri

D=lambda s:0 if s=='?'*len(s)else min(1+D(s[:i]+'?'*(j-i)+s[j:])for i in range(len(s))for j in range(i+1,len(s)+1)if set(s[i:j])-set('?')==set(s[i]))

Uso ?per contrassegnare un'area che può essere di qualsiasi colore. Dseleziona una regione contigua dello stick che contiene solo un singolo colore (più forse alcuni ?s), colora quella regione per ultima, sostituisce quella regione con se ?ricorre per trovare tutti i passaggi precedenti.

Tempo di esecuzione esponenziale. Appena abbastanza veloce per fare gli esempi in un tempo ragionevole (pochi minuti). Scommetto che con la memoizzazione potrebbe essere molto più veloce.


1

Python 3 - 122

def r(s,a):c=s[0];z=c in a;return s[1:]and min([1+r(s[1:],a+c)]+[r(s[1:],a[:a.rfind(c)+1])]*z)or(1-z)
print(r(input(),''))

Sembra funzionare, ma non sono ancora sicuro al 100% che questo metodo troverà sempre il numero minimo di passaggi.


1

CoffeeScript - 183247224 215 207

x=(s,c='')->return 0if !s[0]?;return x s[1..],c if s[0]is c;l=s.length;return x s[1...l],c if s[l-1]is c;i=s.lastIndexOf s[0];1+(x s[1...i],s[0])+x s[i+1..],c
y=(z)->z=z.split "";Math.min (x z),x z.reverse()

Demo su JSFiddle.net

Versione non registrata con codice di debug e commenti:

paintSubstring = (substring, color = '####') ->
  console.log 'Substring and color', substring, color, substring[0]
  # no need to color here
  if !substring[0]?
    return 0
  # no need to recolor the first part
  if substring[0] is color
    return paintSubstring (substring[1..]), color
  l = substring.length
  # no need to recolor the last part
  if substring[l-1] is color
    return paintSubstring substring[0...l], color
  # cover as much as possible
  index = substring.lastIndexOf substring[0]
  part1 = substring[1...index]
  part2 = substring[index+1..]
  console.log 'Part 1:', part1
  console.log 'Part 2:', part2
  # color the rest of the first half
  p1 = paintSubstring part1, substring[0]
  # color the rest of the second half, note that the color did not change!
  p2 = paintSubstring part2, color
  # sum up the cost of the substick + this color action
  return p1+p2+1
paintSubstringX=(x)->Math.min (paintSubstring x.split("")), paintSubstring x.split("").reverse()
console.clear()
input = """YRYGR
grG
GyRyGyG
pbgbrgrp
aaaaaaaa
hyghgy""".split /\n/
for stick in input
  console.log paintSubstringX stick

Sembra restituire un risultato errato per hyghgy. Dice 5 ma dovrebbe essere 4. (tuttavia, restituisce il risultato corretto di 4 per hyghgyh).
PhiNotPi

@PhiNotPi Dio, questo mi ha spinto indietro di oltre 60 caratteri :( Cercando di reimplementarlo in un'altra lingua, dopo aver fatto un pisolino.
TimWolla,

0

Haskell, 143 caratteri

f s=g(r n ' ')0where{r=replicate;n=length s;g p l=minimum$n:[0|p==s]++[1+g(take i p++r(j-i)(s!!i)++drop j p)(l+1)|l<n,i<-[0..n-1],j<-[i+1..n]]}

Questo prova tutte le possibili riscritture fino alla lunghezza della stringa e arriva fino a quando non ne trova una che costruisce il modello di input. Inutile dire che il tempo esponenziale (e poi alcuni).


0

Una prima ampia ricerca semplice. Non mette nulla in coda che è già stato visto. Funziona in meno di un secondo per tutti gli esempi tranne 'pbgbrgrp' che in realtà richiede un minuto intero :(

Ora che ho qualcosa che funziona, lavorerò per trovare qualcosa più veloce e più breve.

Python - 300 296

def f(c):
 k=len(c);q=['0'*99];m={};m[q[0]]=1
 while q:
  u=q.pop(0)
  for x in ['0'*j+h*i+'0'*(k-j-i) for h in set(c) for j in range(1+k) for i in range(1,1+k-j)]:
   n=''.join([r if r!='0' else l for l,r in zip(u,x)])
   if n == c:
     return m[u]
   if not n in m:
    m[n]=m[u]+1;q.append(n)

Potete per favore controllare il rientro? Sembra essere rotto.
Howard,

@Howard fixed. Non ho idea di cosa stavo pensando ieri sera.
TrevorM,

0

Haskell, 118 86 caratteri

p""=0
p(a:s)=1+minimum(map(sum.map p.words)$sequence$map(a%)s)
a%b|a==b=b:" "|1<3=[b]

Esecuzioni di test:

λ: p "YRYGR"
4

λ: p "grG"
3

λ: p "GyRyGyG"
4

λ: p "pbgbrgrp"
5

λ: p "hyghgy"
4

λ: p "abcacba"
4

Questo metodo non è nemmeno così inefficiente!

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.