涂一根棍子需要多长时间?


12

(基于此Math.SE问题,该问题还提供了一些图形)

我有一根看起来像这样的棍子:

在此处输入图片说明

我希望它看起来像这样:

在此处输入图片说明

我不是专业画家,因此,在开始这个雄心勃勃的DIY项目之前,我想确保自己不会感到头疼。

您的程序应该告诉我,画这根棍子需要多少步骤。每个步骤都涉及用纯色绘制连续的区域,该区域覆盖先前的油漆层。对于上面的示例,我可以先将左半部分涂成蓝色,右半部分涂成红色,然后将两个单独的绿色区域分别涂成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类似,但相似。
Kendall Frey 2014年

Answers:


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

对于输入的每个字符,如果我们先绘制该颜色,则计算图案的长度。这是通过假装我们绘制该颜色,然后从不是该颜色的位中制作子部分,然后递归调用它们的paint方法来完成的。返回最短路径。

范例(YRYGR):

最初,尝试R。这给了我们小组YYGY一口气被粉刷一遍。

YG:尝试GY琐碎,长短2。尝试YG琐碎,长度2。YG因此是长度2

R因此绘画首先给我们1 + 1 + 2 = 4

然后尝试G。这给了我们小组YRYRR是微不足道的。

对于YRY

尝试YR小,长度2。尝试RYY是两组,长度3

YRY是长度2

绘画G先给1 + 1 + 2 = 4

然后尝试Y。这给出了子组RGRR琐碎,GR就是长度2Y是长度4

然后,此实现将再次检查R和Y以减少代码长度。对于结果YRYGR,因此是4


我认为您的扩展版本在m某处丢失了var 。
Hasturkun 2014年

不幸的是,您的版本也没有为input提供正确的结果"abcacba"
2014年

@Hasturkun m只是它的简写word.length:) @Howard你是对的,我必须重新考虑一下。
meiamsome 2014年

1

Python,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

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

看来可行,但是我仍然不能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 2014年

@PhiNotPi神,这把我推回超过60个字符:(试图用另一种语言重写本,睡午觉后
TimWolla

0

Haskell,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)

能请您检查缩进吗?好像坏了。
霍华德

@霍华德修复。我不知道昨晚在想什么。
TrevorM 2014年

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

这种方法甚至没有那么低效!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.