막대기를 그리는 데 얼마나 걸립니까?


12

( 이 Math.SE 문제를 바탕으로 일부 그래픽도 제공함)

나는 다음과 같은 막대기를 가지고 있습니다.

여기에 이미지 설명을 입력하십시오

나는 다음과 같이 보이기를 원합니다.

여기에 이미지 설명을 입력하십시오

그러나 저는 전문 화가가 아니기 때문에 야심 찬 DIY 프로젝트를 시작하기 전에 머리가 아프지 않은지 확인하고 싶습니다.

이 스틱을 그리는 데 얼마나 많은 단계가 포함되어 있는지 프로그램에서 알려줍니다. 각 단계에는 단색의 페인트로 연속 영역을 페인트하는 작업이 포함됩니다. 위의 예에서는 왼쪽 절반을 파란색, 오른쪽 절반을 빨간색으로 칠한 다음 두 개의 별도 녹색 영역을 총 4 단계로 칠할 수 있습니다 (녹색은 연속적으로 칠하지 않음).

여기에 이미지 설명을 입력하십시오

다음은 ASCII입니다.

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

이 스틱을 페인트하고 같은 결과를 얻는 몇 가지 방법이 있습니다. 그러나 시간 추정에만 관심이 있습니다. 이는 4 단계입니다.

프로그램은 주어진 색 구성표로 스틱을 칠하는 데 필요한 최소 단계 수를 출력해야합니다. 페인트 구성표는 문자열 형태이며 출력은 숫자입니다. 이것은 코드 골프입니다. 최단 프로그램이 이깁니다.

입력

당신의 프로그램은 문자의 형태로 막대기에 대한 채색 체계를 받게됩니다. 각 고유 문자 (대소 문자 구분)는 고유 한 색상을 나타냅니다.

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

답변:


3

GolfScript, 82 72 67 자

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

GolfScript 프로그램에 대해 상당히 빠른 예 :

> hyghgy
4

> pbgbrgrp
5

사용 된 알고리즘은 다음 명령문에 따라 왼쪽에서 오른쪽으로 재귀 적으로 색상을 통해 작동합니다.

  • 왼쪽에서 이미 필요한 색상을 가진 모든 부분을 무시하십시오. 다시 페인트 칠하면 더 나은 답변을 얻을 수 없습니다.
  • 전체 스틱에 원하는 색상이 이미 있으면 결과적으로 0 단계를 반환합니다.
  • 그렇지 않으면, 가장 왼쪽 부분 (즉, 원하는 색이 아닌 첫 번째 부분)의 대상 색상을 선택하십시오.

    • 대상 색상으로 1 부분을 페인트하고 재귀하십시오.
    • 이 색으로 두 부분을 칠하고 재귀하십시오.

    ...

    • 남은 스틱 전체를이 색으로 칠하고 재귀하십시오.

    모든 숫자의 최소값을 취하고 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!단계 인 것 같습니다 .) (그러나 아마도 이것이 진짜 복잡 할 것입니다.
yo '

2

자바 스크립트 : 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: YY, 길이를 두 그룹입니다 3.

YRY길이 2입니다.

G먼저 그림 제공1 + 1 + 2 = 4

그런 다음 시도하십시오 Y. 이 하위 그룹을 제공 R하고 GR. R사소한 GR길이 2입니다. Y길이입니다4

이 구현은 코드 길이를 줄이기 위해 R과 Y를 다시 확인합니다. 따라서 결과는 YRYGR입니다 4.


확장 된 버전이 m어딘가 에서 var를 잃어 버린 것 같습니다 .
Hasturkun

불행히도, 귀하의 버전은 input에 대한 올바른 결과를 제공하지 않습니다 "abcacba".
Howard

@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

커피 스크립트 - 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

간단한 폭의 첫 번째 검색. 이미 본 대기열에는 아무것도 넣지 않습니다. 모든 예제에서 1 초 안에 작동하지만 실제로는 전체 시간이 걸리는 '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

@Howard가 수정되었습니다. 어제 밤에 무슨 생각을했는지 모르겠습니다.
TrevorM

0

하스켈, 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

이 방법은 그다지 비효율적입니다!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.