Wie lange dauert es, einen Stock zu malen?

12

(Basierend auf diesem Math.SE-Problem , das auch einige Grafiken enthält)

Ich habe einen Stock, der ungefähr so ​​aussieht:

Bildbeschreibung hier eingeben

Ich möchte, dass es so aussieht:

Bildbeschreibung hier eingeben

Ich bin jedoch kein erfahrener Maler. Bevor ich also ein so ehrgeiziges DIY-Projekt beginne, möchte ich sicherstellen, dass ich nicht über den Kopf komme.

Ihr Programm sollte mir sagen, wie viele Schritte zum Malen dieses Sticks erforderlich sind. Bei jedem Schritt wird ein durchgehender Bereich mit einer Volltonfarbe angestrichen, mit der vorherige Farbschichten abgedeckt werden. Für das obige Beispiel könnte ich die linke Hälfte blau, die rechte Hälfte rot und dann die zwei getrennten grünen Bereiche für insgesamt 4 Schritte malen (das Grün wird nicht durchgehend gemalt).

Bildbeschreibung hier eingeben

Hier ist es in ASCII:

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

Es gibt verschiedene Möglichkeiten, diesen Stift zu bemalen und das gleiche Ergebnis zu erzielen. Mich interessiert allerdings nur die Zeitschätzung, die vier Schritte umfasst.

Tor

Ihr Programm sollte die Mindestanzahl von Schritten ausgeben, die zum Malen eines Sticks mit einem bestimmten Farbschema erforderlich sind. Das Malschema wird in Form einer Zeichenfolge dargestellt, während die Ausgabe eine Zahl ist. Das ist Code Golf. Kürzeste Sendung gewinnt.

Eingang

Ihr Programm erhält das Farbschema für einen Stick in Form einer Buchstabenfolge. Jeder eindeutige Buchstabe (Groß- und Kleinschreibung beachten) steht für eine eindeutige Farbe.

YRYGR

grG

GyRyGyG

pbgbrgrp

hyghgy

Ausgabe

Diese Zahlen entsprechen der geringsten Anzahl von Schritten, die zum Bemalen der Stifte erforderlich sind.

4

3

4

5

4

Erklärungen

So bin ich zu den oben genannten Zahlen gekommen. Ihr Programm muss dies nicht ausgeben:

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

 ---
 g--
 gr-
 grG

 -------
 GGGGGGG
 GyyyGGG
 GyRyGGG
 GyRyGyG

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

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

Bearbeiten: Ich werde mehr Testfälle hinzufügen, wenn sie sich als schwierigere Testfälle herausstellen.

PhiNotPi
quelle
Dies erinnert mich an stackoverflow.com/q/10364248/785745 , was ähnlich ist, aber in 2D.
Kendall Frey

Antworten:

3

GolfScript, 82 72 67 Zeichen

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

Ziemlich schnell für ein GolfScript-Programm, Beispiele:

> hyghgy
4

> pbgbrgrp
5

Der verwendete Algorithmus durchläuft die Farben rekursiv von links nach rechts gemäß den folgenden Anweisungen:

  • Ignorieren Sie alle Teile von links, die bereits die gewünschte Farbe haben. Ein erneutes Übermalen liefert keine bessere Antwort.
  • Wenn der komplette Stick bereits die gewünschte Farbe hat, geben Sie als Ergebnis 0 Schritte zurück.
  • Andernfalls nehmen Sie die Zielfarbe des jetzt ganz linken Teils (dh die erste nicht in der gewünschten Farbe).

    • Malen Sie 1 Teil mit der Zielfarbe und wiederholen Sie den Vorgang.
    • Malen Sie 2 Teile mit dieser Farbe und recurse.

    ...

    • Malen Sie den gesamten verbleibenden Stab mit dieser Farbe und wiederholen Sie den Vorgang.

    Nehmen Sie das Minimum all dieser Zahlen und addieren Sie 1 (für den aktuellen Schritt). Geben Sie dies als die optimale Anzahl von Schritten zurück.

Dieser Algorithmus funktioniert, weil der linke Teil sowieso auf einmal gezeichnet werden muss. Warum also nicht sofort - auf jede mögliche Weise.

.,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
Howard
quelle
+1 für den Algorithmus "Farbe ganz links falsch". Es scheint jedoch n!Schritte zu sein;) (aber vielleicht ist dies die wahre Komplexität, keine Ahnung).
Du
2

JavaScript: 187 Bytes

Angenommen, wir dürfen nur die Ein- und Ausgabe für eine Funktion haben (bitte)!

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 Bytes durch weitere hässliche Optimierung (was ein Teil des Punktes ist, und ich fand es unglaublich lustig):

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 Bytes Ich habe festgestellt, dass die Länge der Eingabe eine Obergrenze ist und ich jetzt keine trivialen Fälle mehr separat behandeln muss.

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}

Testfälle:

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

Erweiterte Version:

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

Berechnen Sie für jedes Zeichen der Eingabe die Länge des Musters, wenn Sie diese Farbe zuerst malen. Dies geschieht, indem wir so tun, als würden wir diese Farbe malen und dann aus den Bits, die nicht diese Farbe haben, Unterabschnitte erstellen und die Malmethode rekursiv aufrufen. Der kürzeste Weg wird zurückgegeben.

Beispiel ( YRYGR):

Versuchen Sie es zunächst R. Dies gibt uns die Untergruppen Yund YG. Ywird trivial in einem Rutsch gemalt.

Für YG: Versuchen Sie G, Yist trivial, Länge 2. Versuchen Sie Y, Gist trivial, Länge 2. YGist also Länge2 .

Das Malen Rgibt uns also zuerst1 + 1 + 2 = 4

Dann versuche es G. Dies gibt uns die Untergruppen YRYund R. Rist trivial.

Für YRY:

Versuchen Sie Y: Rist trivial, Länge 2. Versuchen Sie R: Yund Ysind die beiden Gruppen, Länge 3.

YRYist Länge 2.

Malen Gzuerst gibt1 + 1 + 2 = 4

Dann versuche es Y. Dies gibt den Untergruppen Rund GR. Rtrivial GRist die Länge 2. Yist Länge4

Diese Implementierung würde dann R und Y erneut prüfen, um die Codelänge zu verringern. Das Ergebnis für YRYGRist daher 4.

meiamsome
quelle
Ich denke, Ihre erweiterte Version hat den var mirgendwo verloren.
Hasturkun
Leider liefert auch Ihre Version nicht das richtige Ergebnis zur Eingabe "abcacba".
Howard
@Hasturkun mwar nur eine Abkürzung für word.length:) @Howard Du hast recht, ich muss das überdenken.
Meiamsome
1

Python, 149 Zeichen

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

Ich benutze ?, um einen Bereich zu markieren, der eine beliebige Farbe haben kann. Dwählt eine zusammenhängende Region des Sticks aus, die nur eine einzige Farbe enthält (plus möglicherweise einige ?s), färbt diese Region zuletzt, ersetzt diese Region durch ?s und sucht erneut nach allen vorherigen Schritten.

Exponentielle Laufzeit. Gerade noch schnell genug, um die Beispiele in einer angemessenen Zeit (ein paar Minuten) zu erstellen. Ich wette mit Memo könnte es viel schneller sein.

Keith Randall
quelle
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(),''))

Es scheint zu funktionieren, aber ich bin immer noch nicht zu 100% sicher, dass diese Methode immer die Mindestanzahl von Schritten findet.

grc
quelle
1

CoffeeScript - 183 247 224 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 auf JSFiddle.net

Ungolfed-Version mit Debug-Code und Kommentaren:

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
TimWolla
quelle
Scheint ein falsches Ergebnis für zurückzugeben hyghgy. Hier steht 5, aber es sollte 4 sein. (Es wird jedoch das korrekte Ergebnis von 4 für zurückgegeben. hyghgyh)
PhiNotPi
@PhiNotPi Gott, das hat mich über 60 Zeichen zurückgedrängt :( Versucht, dies in einer anderen Sprache zu implementieren, nachdem ich ein Nickerchen gemacht habe.
TimWolla
0

Haskell, 143 Zeichen

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

Dadurch werden alle möglichen Umschreibungen bis zur Länge der Zeichenfolge versucht und es wird eine gefunden, die das Eingabemuster erstellt. Unnötig zu sagen, exponentielle Zeit (und dann einige).

Pseudonym
quelle
0

Eine einfache erste Suche. Es wird nichts in die Warteschlange gestellt, was bereits gesehen wurde. Es funktioniert in weniger als einer Sekunde für alle Beispiele, aber 'pbgbrgrp', was tatsächlich eine volle Minute dauert :(

Jetzt, da ich etwas habe, das funktioniert, werde ich daran arbeiten, etwas schneller und kürzer zu finden.

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)
TrevorM
quelle
Können Sie bitte den Einzug überprüfen? Es scheint kaputt zu sein.
Howard
@ Howard behoben. Ich habe keine Ahnung, was ich letzte Nacht gedacht habe.
TrevorM
0

Haskell, 118 86 Zeichen

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

Testläufe:

λ: p "YRYGR"
4

λ: p "grG"
3

λ: p "GyRyGyG"
4

λ: p "pbgbrgrp"
5

λ: p "hyghgy"
4

λ: p "abcacba"
4

Diese Methode ist gar nicht so ineffizient!

MtnViewMark
quelle