Bir çubuğu boyamak ne kadar sürer?


12

( Bazı grafikler de sağlayan bu Math.SE problemine dayanarak )

Ben böyle bir sopa var:

resim açıklamasını buraya girin

Bunun gibi görünmesini istiyorum:

resim açıklamasını buraya girin

Bununla birlikte, uzman bir ressam değilim, bu yüzden iddialı bir DIY projesine başlamadan önce, başımın üstünde olmadığımdan emin olmak istiyorum.

Programınız bana bu çubuğu boyamak için kaç adımın dahil olduğunu söylemelidir. Her adım, önceki boya katmanlarını kapsayan düz bir renkle sürekli bir alanın boyanmasını içerir. Yukarıdaki örnek için, sol yarıyı mavi, sağ yarısını kırmızı ve ardından iki ayrı yeşil alanı toplam 4 adımda boyayabilirim (yeşil sürekli boyanmaz).

resim açıklamasını buraya girin

İşte ASCII'de:

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

Bu çubuğu boyamanın ve aynı sonuçla sonuçlanmanın birkaç farklı yolu vardır. Ben sadece zaman tahmini ile ilgileniyorum, ancak bu dört adım.

Hedef

Programınız, belirli bir renk şemasına sahip bir çubuğu boyamak için gereken minimum adım sayısını vermelidir. Boya şeması bir karakter dizisi biçiminde olurken çıktı bir sayı olacaktır. Bu kod golf. En kısa program kazanır.

Giriş

Programınız bir dizi harf şeklinde bir çubuğun renklendirme şemasını alacaktır. Her benzersiz harf (büyük / küçük harfe duyarlı) benzersiz bir rengi temsil eder.

YRYGR

grG

GyRyGyG

pbgbrgrp

hyghgy

Çıktı

Bu sayılar, çubukları boyamak için gereken en az adımdır.

4

3

4

5

4

açıklamalar

Yukarıdaki sayılara bu şekilde ulaştım. Programınızın bunun çıktısını almasına gerek yoktur:

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

 ---
 g--
 gr-
 grG

 -------
 GGGGGGG
 GyyyGGG
 GyRyGGG
 GyRyGyG

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

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

Düzenleme: Daha zor test senaryoları olduklarını kanıtlarsanız daha fazla test örneği ekleyeceğim.


Bu bana benzer, ancak 2B olarak stackoverflow.com/q/10364248/785745 hatırlatıyor .
Kendall Frey

Yanıtlar:


3

GolfScript, 82 72 67 karakter

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

Bir GolfScript programı için oldukça hızlı örnekler:

> hyghgy
4

> pbgbrgrp
5

Kullanılan algoritma, aşağıdaki ifadelere göre soldan sağa renkler arasında özyineli olarak çalışır:

  • Soldan gerekli renge sahip tüm parçaları yok sayın. Onları yeniden boyamak daha iyi bir cevap vermeyecektir.
  • Çubuğun tamamı zaten istenen renge sahipse, sonuç olarak 0 adım döndürün.
  • Aksi takdirde, en soldaki parçanın hedef rengini alın (yani ilk istenen renkte değil).

    • 1 kısım hedef renk ve çukur boya ile boyayın.
    • Bu renk ve çukur ile 2 parça boyayın.

    ...

    • Kalan tüm çubuğu bu renk ve çukur ile boyayın.

    Tüm bu sayıların minimumunu alın ve 1'i ekleyin (geçerli adım için). Bunu en uygun adım sayısı olarak döndürün.

Bu algoritma çalışır, çünkü en soldaki kısım yine de bir kerede boyanmalıdır, bu yüzden neden hemen yapmıyorsunuz - olası herhangi bir şekilde.

.,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 "en soldaki renk yanlış" algoritması için. Ancak, n!adımlar gibi görünüyor ;) (ama belki de bu gerçek karmaşıklıktır, bilmiyorum).
yo'

2

JavaScript: 187 Bayt

Bir işlevin giriş ve çıkışına izin verdiğimizi varsayarsak (lütfen)!

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 Bayt daha çirkin optimizasyon yaparak (Bu bir parçasıdır ve inanılmaz eğlenceli buldum):

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 Bayt Girdi uzunluğunun bir üst sınır olduğunu fark ettim ve şimdi önemsiz vakaları ayrı ayrı ele almam gerekmiyor.

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}

Test senaryoları:

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

Genişletilmiş sürüm:

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

Girişin her karakteri için, önce o rengi boyadığımızda desenin uzunluğunu hesaplayın. Bu, o rengi boyadığımızı iddia ederek ve sonra o renk olmayan bitlerden alt bölümler yaparak ve özyinelemeleri üzerinde boya yöntemini çağırarak yapılır. En kısa yol döndürülür.

Örnek ( YRYGR):

Başlangıçta deneyin R. Bu bize alt grupları verir Yve YG. Yönemsiz bir şekilde boyanmış.

İçin YG: Deneyin G, Yönemsiz, uzunluk 2. Deneyin Y, Gönemsiz, uzunluk 2. YGbu nedenle uzunluk 2.

RÖnce resim yapmak bize1 + 1 + 2 = 4

Sonra deneyin G. Bu bize alt grupları verir YRYve R. Rönemsizdir.

Şunun için YRY:

Deneyin Y: Rönemsiz, uzunluk 2. Deneyin R: Yve Yiki grup, uzunluk 3.

YRYuzunluk 2.

Resim Gilk verir1 + 1 + 2 = 4

Sonra deneyin Y. Bu alt gruplara Rve verir GR. Rönemsiz, GRuzunluk 2. Yuzunluk4

Bu uygulama daha sonra kod uzunluğunu azaltmak için R ve Y'yi tekrar kontrol edecektir. Bu YRYGRnedenle sonuç şudur 4.


Ben senin genişletilmiş versiyonu var bir myerde kaybetti düşünüyorum .
Hasturkun

Ne yazık ki, sürümünüz de giriş için doğru sonucu vermiyor "abcacba".
Howard

@Hasturkun mkısaca word.length:) @Howard Doğru, bunu tekrar düşünmem gerekecek.
meiamsome

1

Python, 149 karakter

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

?Herhangi bir renk olabilecek bir alanı işaretlemek için kullanıyorum . Dçubuğun yalnızca tek bir renk (artı belki bazı ?s), bitişik renkler içeren bitişik bir bölgesini seçer ?, önceki tüm adımları bulmak için o bölgeyi s ile değiştirir ve tekrarlar.

Üstel çalışma süresi. Sadece makul bir sürede (birkaç dakika) örnekleri yapmak için yeterince hızlı. Bahse girerim çok daha hızlı olabilir.


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

Çalışıyor gibi görünüyor, ancak bu yöntemin her zaman minimum adım sayısını bulacağından% 100 emin değilim.


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

JSFiddle.net üzerinde demo

Hata ayıklama kodu ve yorumları içeren yorumlanmamış sürüm:

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

İçin yanlış bir sonuç döndürüyor gibi görünüyor hyghgy. 5 diyor ama 4 olmalı. (Ancak, 4 için doğru sonucu döndürür hyghgyh).
PhiNotPi

@PhiNotPi Tanrım, bu beni 60 karakterden fazla geri itti :( Şekerleme yaptıktan sonra bunu başka bir dilde yeniden uygulamaya çalışıyorum.
TimWolla

0

Haskell, 143 karakter

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

Bu, tüm olası yeniden yazma işlemlerini dizenin uzunluğuna kadar dener ve girdi desenini oluşturan birini bulana kadar gider. Söylemeye gerek yok, üstel zaman (ve sonra bazı).


0

Basit bir genişlik ilk arama. Daha önce görülen kuyruğa hiçbir şey koymaz. Tüm örnekler için bir saniyenin altında çalışır, ancak aslında tam bir dakika süren 'pbgbrgrp' :(

Artık işe yarayan bir şeyim olduğuna göre daha hızlı ve daha kısa bir şey bulmak için çalışacağım.

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)

Girintiyi kontrol edebilir misiniz? Kırılmış gibi görünüyor.
Howard

@ Sabit düzeltildi. Dün gece ne düşündüğüm hakkında hiçbir fikrim yok.
TrevorM

0

Haskell, 118 86 karakter

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

Test çalıştırmaları:

λ: p "YRYGR"
4

λ: p "grG"
3

λ: p "GyRyGyG"
4

λ: p "pbgbrgrp"
5

λ: p "hyghgy"
4

λ: p "abcacba"
4

Bu yöntem o kadar verimsiz bile değil!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.