スティックをペイントするにはどれくらい時間がかかりますか?


12

このMath.SE問題に基づいて、グラフィックも提供します)

私はこのように見える棒を持っています:

ここに画像の説明を入力してください

私はそれをちょっとこのように見せたいです:

ここに画像の説明を入力してください

私は専門の画家ではありませんが、このような野心的なDIYプロジェクトを始める前に、頭の中にいないことを確認したいと思います。

あなたのプログラムは、このスティックをペイントするのにいくつのステップが必要かを教えてくれるはずです。各ステップでは、前のペイント層を覆う無地の連続領域をペイントします。上記の例では、左半分を青、右半分を赤、そして2つの別々の緑の領域を合計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です。
ケンドールフレイ14年

回答:


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!ステップのようです;)(しかし、これは本当の複雑さかもしれません、私は知らない)。
yo

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い最適化を行うことで 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:試してみてGYささいな、長さです2です。試してみてくださいYG長さ2 YGです2。したがって、長さです。

Rしたがって、最初にペイントすると1 + 1 + 2 = 4

それから試してくださいG。これにより、サブグループが提供されますYRYとが得られRます。R簡単です。

のためにYRY

試してくださいYRささいな、長さ2です。試してくださいRYそしてY、2つのグループ、長さです3です。

YRY 長さです 2です。

ペインティング G最初に1 + 1 + 2 = 4

それから試してくださいY。これにより、サブグループRとが得られGRます。Rつまらない、GR長さ2です。Y長さです4

この実装では、RとYを再度チェックして、コード長を減らします。YRYGRしたがって、の結果はです4


拡張バージョンはmどこかで変数を失ったと思います。
ハスタークン14年

残念ながら、あなたのバージョンでもinputに対して正しい結果が得られません"abcacba"
ハワード14年

@Hasturkun mword.length:)の省略形でした。@ Howardあなたは正しいです、私はこれを再考しなければなりません。
meiamsome

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 14年

@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'以外のすべての例では1秒未満で動作しますが、実際には1分かかります:(

今、私が何かを持っている作品、私はより速く、より短く何かを見つけることに作業になりますが。

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)

インデントを確認してください。壊れているようです。
ハワード14年

@Howardが修正されました。昨夜私が何を考えていたのか分かりません。
TrevorM 14年

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

この方法はそれほど効率的ではありません!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.