Combien de temps faut-il pour peindre un bâton?

12

(Basé sur ce problème Math.SE , qui fournit également des graphiques)

J'ai un bâton qui ressemble un peu à ceci:

entrez la description de l'image ici

Je veux que ça ressemble un peu à ceci:

entrez la description de l'image ici

Je ne suis pas un peintre expert, cependant, avant de commencer un projet de bricolage aussi ambitieux, je veux m'assurer que je ne suis pas au-dessus de ma tête.

Votre programme devrait me dire combien d'étapes sont nécessaires pour peindre ce bâton. Chaque étape consiste à peindre une zone continue avec une couleur unie, qui recouvre les couches précédentes de peinture. Pour l'exemple ci-dessus, je pourrais peindre la moitié gauche bleue, la moitié droite rouge, puis les deux zones vertes séparées pour un total de 4 étapes (le vert n'est pas continuellement peint).

entrez la description de l'image ici

Le voici en ASCII:

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

Il y a deux façons différentes de peindre ce bâton et de se retrouver avec le même résultat. Cependant, je ne m'intéresse qu'à l'estimation du temps, qui est en quatre étapes.

Objectif

Votre programme doit produire le nombre minimum d'étapes nécessaires pour peindre un bâton avec une palette de couleurs donnée. Le schéma de peinture sera sous la forme d'une chaîne de caractères, tandis que la sortie sera un nombre. C'est le golf de code. Le programme le plus court gagne.

Contribution

Votre programme recevra le schéma de coloration d'un bâton sous la forme d'une chaîne de lettres. Chaque lettre unique (sensible à la casse) représente une couleur unique.

YRYGR

grG

GyRyGyG

pbgbrgrp

hyghgy

Production

Ces nombres sont le moins d'étapes nécessaires pour peindre les bâtons.

4

3

4

5

4

Explications

C'est ainsi que je suis arrivé aux chiffres ci-dessus. Votre programme n'a pas besoin de produire ceci:

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

 ---
 g--
 gr-
 grG

 -------
 GGGGGGG
 GyyyGGG
 GyRyGGG
 GyRyGyG

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

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

Edit: je vais ajouter plus de cas de test s'ils s'avèrent être des cas de test plus difficiles.

PhiNotPi
la source
Cela me rappelle stackoverflow.com/q/10364248/785745 , qui est similaire, mais en 2D.
Kendall Frey

Réponses:

3

GolfScript, 82 72 67 caractères

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

Raisonnablement rapide pour un programme GolfScript, exemples:

> hyghgy
4

> pbgbrgrp
5

L'algorithme utilisé fonctionne à travers les couleurs de gauche à droite de manière récursive, selon les instructions suivantes:

  • Ignorez toutes les parties de la gauche qui ont déjà la couleur requise. Les repeindre ne fournira pas de meilleure réponse.
  • Si le stick complet a déjà la couleur désirée, retournez 0 pas comme résultat.
  • Sinon, prenez la couleur cible de la partie maintenant la plus à gauche (c'est-à-dire la première pas dans la couleur souhaitée).

    • Peignez 1 partie avec la couleur cible et reprenez.
    • Peignez 2 parties avec cette couleur et recuisez.

    ...

    • Peignez tout le bâton restant avec cette couleur et recuisez.

    Prenez le minimum de tous ces nombres et ajoutez 1 (pour l'étape en cours). Renvoyez-le comme le nombre optimal d'étapes.

Cet algorithme fonctionne, car la partie la plus à gauche doit être peinte à tout moment, alors pourquoi ne pas le faire immédiatement - de toute façon possible.

.,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
la source
+1 pour l'algorithme "couleur la plus à gauche". Cependant, cela semble être des n!étapes;) (mais c'est peut-être la vraie complexité, je ne sais pas).
yo '
2

JavaScript: 187 octets

En supposant que nous sommes autorisés à avoir juste l'entrée et la sortie d'une fonction (s'il vous plaît)!

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 octets en faisant une optimisation plus laide (ce qui fait partie du point, et j'ai trouvé incroyablement amusant):

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 octets J'ai réalisé que la longueur de l'entrée est une limite supérieure et je n'ai plus besoin de gérer les cas triviaux séparément maintenant.

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}

Cas de test:

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

Version étendue:

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

Pour chaque caractère de l'entrée, calculez la longueur du motif si nous peignons cette couleur en premier. Cela se fait en prétendant que nous peignons cette couleur, puis en créant des sous-sections à partir des bits qui ne sont pas de cette couleur, et en appelant récursivement la méthode de peinture sur eux. Le chemin le plus court est renvoyé.

Exemple ( YRYGR):

Au départ, essayez R. Cela nous donne les sous-groupes Yet YG. Yest trivialement peint en une seule fois.

Pour YG: Essayez G, Yc'est trivial, la longueur 2. Essayez Y, Gest trivial, la longueur 2. YGest donc la longueur 2.

La peinture Rnous donne donc d'abord1 + 1 + 2 = 4

Alors essayez G. Cela nous donne les sous-groupes YRYet R. Rest trivial.

Pour YRY:

Essayez Y: Rest trivial, la longueur 2. Essayez R: Yet Ysont les deux groupes, la longueur 3.

YRYest la longueur 2.

La peinture Gdonne d'abord1 + 1 + 2 = 4

Alors essayez Y. Cela donne les sous-groupes Ret GR. Rtrivial, GRc'est la longueur 2. Yest la longueur4

Cette implémentation vérifierait alors à nouveau R et Y pour réduire la longueur du code. Le résultat pour YRYGRest donc 4.

meiamsome
la source
Je pense que votre version étendue a perdu la var mquelque part.
Hasturkun
Malheureusement, votre version ne donne pas non plus le résultat correct pour la saisie "abcacba".
Howard
@Hasturkun métait juste un raccourci pour word.length:) @Howard Vous avez raison, je vais devoir repenser cela.
meiamsome
1

Python, 149 caractères

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

J'utilise ?pour marquer une zone qui peut être de n'importe quelle couleur. Dsélectionne une région contiguë du bâton qui ne contient qu'une seule couleur (plus peut-être quelques ?s), les couleurs de cette région en dernier, remplace cette région par ?s et revient pour trouver toutes les étapes précédentes.

Durée de fonctionnement exponentielle. À peine assez rapide pour faire les exemples dans un délai raisonnable (quelques minutes). Je parie que la mémorisation pourrait être beaucoup plus rapide.

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

Cela semble fonctionner, mais je ne suis toujours pas sûr à 100% que cette méthode trouvera toujours le nombre minimum d'étapes.

grc
la source
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()

Démo sur JSFiddle.net

Version non golfée incluant le code de débogage et les commentaires:

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
la source
Semble renvoyer un résultat incorrect pour hyghgy. Il indique 5 mais il devrait être 4. (cependant, il renvoie le résultat correct de 4 pour hyghgyh).
PhiNotPi
@PhiNotPi Dieu, cela m'a repoussé de plus de 60 caractères :( J'essaie de réimplémenter cela dans une autre langue, après avoir fait une sieste.
TimWolla
0

Haskell, 143 caractères

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

Cela essaie toutes les réécritures possibles jusqu'à la longueur de la chaîne et va jusqu'à ce qu'il en trouve une qui construit le modèle d'entrée. Inutile de dire le temps exponentiel (et puis certains).

Pseudonyme
la source
0

Une première recherche simple. Il ne met rien dans la file d'attente qui a déjà été vu. Cela fonctionne en moins d'une seconde pour tous les exemples, mais 'pbgbrgrp' qui prend en fait une minute entière :(

Maintenant que j'ai quelque chose qui fonctionne, je vais essayer de trouver quelque chose de plus rapide et de plus court.

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
la source
Pouvez-vous s'il vous plaît vérifier l'indentation? Il semble être cassé.
Howard
@Howard fixe. Je n'ai aucune idée de ce que je pensais hier soir.
TrevorM
0

Haskell, 118 86 caractères

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

Essais:

λ: p "YRYGR"
4

λ: p "grG"
3

λ: p "GyRyGyG"
4

λ: p "pbgbrgrp"
5

λ: p "hyghgy"
4

λ: p "abcacba"
4

Cette méthode n'est même pas si inefficace!

MtnViewMark
la source