Скільки часу потрібно, щоб фарбувати паличку?


12

(Виходячи з цієї проблеми Math.SE , яка також містить деяку графіку)

У мене палиця, яка виглядає приблизно так:

введіть тут опис зображення

Я хочу, щоб це виглядало приблизно так:

введіть тут опис зображення

Однак я не є живописцем-експертом, тому, перш ніж розпочати такий амбітний проект самостійно, хочу переконатися, що мені це не над головою.

Ваша програма повинна сказати мені, скільки кроків бере участь у малюванні цієї палички. Кожен крок передбачає фарбування суцільної області суцільним кольором, який покриває попередні шари фарби. Для наведеного вище прикладу я міг пофарбувати ліву половину в синій, праву половину в червону, а потім дві окремі зелені зони в цілому 4 кроки (зелений не пофарбований постійно).

введіть тут опис зображення

Ось це в ASCII:

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

Існує кілька різних способів намалювати цю паличку і в кінцевому підсумку досягти однакового результату. Мене цікавить лише оцінка часу, однак це чотири кроки.

Мета

Ваша програма повинна вивести мінімальну кількість кроків, необхідних для фарбування палички із заданою кольоровою гамою. Схема фарби буде у вигляді рядка символів, а вихідний буде числом. Це код гольфу. Найкоротша програма виграє.

Вхідні дані

Ваша програма отримає схему забарвлення палички у вигляді рядка літер. Кожна унікальна літера (з урахуванням регістру) являє собою унікальний колір.

YRYGR

grG

GyRyGyG

pbgbrgrp

hyghgy

Вихідні дані

Ці цифри - найменша кількість кроків, необхідних для фарбування паличок.

4

3

4

5

4

Пояснення

Ось як я дійшов до вищеназваних номерів. Вашій програмі не потрібно цього виводити:

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

 ---
 g--
 gr-
 grG

 -------
 GGGGGGG
 GyyyGGG
 GyRyGGG
 GyRyGyG

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

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

Редагувати: Я додаю більше тестових випадків, якщо вони виявляться складнішими тестовими.


Це нагадує мені stackoverflow.com/q/10364248/785745 , який схожий, але в 2D.
Кендалл Фрей

Відповіді:


3

GolfScript, 82 72 67 символів

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

Досить швидко для програми GolfScript, приклади:

> hyghgy
4

> pbgbrgrp
5

Використовуваний алгоритм працює через кольори зліва направо на рекурсивно, відповідно до таких тверджень:

  • Ігноруйте всі частини зліва, які вже мають потрібний колір. Перефарбування їх знову не дасть кращої відповіді.
  • Якщо цільна паличка вже має потрібний колір, поверніть як результат 0 кроків.
  • В іншому випадку візьміть цільовий колір крайньої лівої частини (тобто першого, не потрібного кольору).

    • Зафарбуйте 1 частину цільовим кольором і повторіть.
    • Зафарбуйте 2 частини цим кольором і повторіть.

    ...

    • Пофарбуйте цілу паличку цілим кольором і повторіть.

    Візьміть мінімум усіх цих чисел і додайте 1 (для поточного кроку). Поверніть це як оптимальну кількість кроків.

Цей алгоритм працює, тому що крайню ліву частину потрібно будь-коли пофарбувати за один раз, то чому б це не зробити негайно - будь-яким можливим способом.

.,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 для алгоритму "кольоровий крайній лівий неправильний". Однак, схоже, це n!кроки;) (але, можливо, це справжня складність, я не знаю).
йо '

2

JavaScript: 187 байт

Припустимо, що нам дозволяється просто мати вхід і вихід у функцію (будь ласка)!

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 байт , роблячи подальшу некрасиву оптимізацію (що є частиною моменту, і мені здалося неймовірно веселим):

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 Байт Я зрозумів, що довжина вводу - це верхня межа, і мені зараз не потрібно окремо обробляти тривіальні випадки.

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}

Тестові приклади:

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

Розширена версія:

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

Для кожного символу введення обчисліть довжину візерунка, якщо ми спочатку пофарбуємо цей колір. Це робиться, роблячи вигляд, що ми фарбуємо цей колір, а потім робимо підрозділи з бітів, які не є цим кольором, і рекурсивно викликаючи метод фарби на них. Повертається найкоротший шлях.

Приклад ( YRYGR):

Спочатку спробуйте R. Це дає нам підгрупи Yта YG. Yтривіально розписаний за один хід.

Для YG: Спробуйте G, Yтривіально, довжина 2. Спробуйте Y, Gтривіально, довжина 2. YGтому довжина 2.

RТому живопис спочатку дає нам1 + 1 + 2 = 4

Потім спробуйте G. Це дає нам підгрупи YRYта R. Rтривіально.

Для YRY:

Спробуйте Y: Rтривіально, довжина 2. Спробуйте R: Yі Yдві групи, довжина 3.

YRY- довжина 2.

Живопис Gспочатку дає1 + 1 + 2 = 4

Потім спробуйте Y. Це дає підгрупи Rі GR. Rтривіальний, GR- довжина 2. Y- довжина4

Потім ця реалізація знову перевірить R і Y, щоб зменшити довжину коду. Результат для YRYGRтому 4.


Я думаю, що ваша розширена версія mдесь загубила вар .
Hasturkun

На жаль, також ваша версія не дає правильного результату для введення даних "abcacba".
Говард

@Hasturkun mбув просто скороченням для word.length:) @Howard Ви маєте рацію, мені доведеться передумати це.
meiamsome

1

Пітон, 149 символів

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

Я використовую ?для позначення області, яка може бути будь-якого кольору. Dвибирає суміжну область палички, яка містить лише один колір (плюс, можливо, кілька ?s), кольори, які останній регіон триває, замінює цю область ?s і повторює пошук усіх попередніх кроків.

Експоненційний час роботи. Лише досить швидко, щоб зробити приклади в розумний час (кілька хвилин). Б'юсь об заклад, з запам'ятовуванням це може бути набагато швидше.


1

Пітон 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(),''))

Здається, це працює, але я все ще не на 100% впевнений, що цей метод завжди знайде мінімальну кількість кроків.


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

Невикористана версія, включаючи код налагодження та коментарі:

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

З'являється повернення неправильного результату для hyghgy. Він говорить 5, але він повинен бути 4. (однак, він повертає правильний результат 4 для hyghgyh).
PhiNotPi

@PhiNotPi Боже, це підштовхнуло мене понад 60 символів :( Намагаючись повторно реалізувати це іншою мовою, після того, як подрімати.
TimWolla

0

Хаскелл, 143 ч

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

Це спробує всі можливі переписування до довжини рядка і триває, поки не знайде той, який будує шаблон введення. Потрібно сказати, експоненціальний час (і то якийсь час).


0

Простий широта першого пошуку. Він нічого не ставить у чергу, яку вже бачили. Він працює за секунду для всіх прикладів, але 'pbgbrgrp', що фактично займає повну хвилину :(

Тепер, коли у мене щось працює, я працюю над тим, щоб знайти щось швидше і коротше.

Пітон - 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)

Чи можете ви перевірити відступ? Здається, зламаний.
Говард

@Howard виправлено. Я поняття не маю, що я думав минулої ночі.
TrevorM

0

Haskell, 118 86 символів

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

Випробування:

λ: p "YRYGR"
4

λ: p "grG"
3

λ: p "GyRyGyG"
4

λ: p "pbgbrgrp"
5

λ: p "hyghgy"
4

λ: p "abcacba"
4

Цей метод навіть не все є неефективним!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.