Berapa lama untuk melukis tongkat?

12

(Berdasarkan masalah Math.SE ini , yang juga menyediakan beberapa grafik)

Saya memiliki tongkat yang terlihat seperti ini:

masukkan deskripsi gambar di sini

Saya ingin terlihat seperti ini:

masukkan deskripsi gambar di sini

Saya bukan pelukis ahli, jadi sebelum saya memulai proyek DIY yang ambisius, saya ingin memastikan bahwa saya tidak berada di atas kepala saya.

Program Anda harus memberi tahu saya berapa banyak langkah yang terlibat dalam mengecat tongkat ini. Setiap langkah melibatkan lukisan area yang kontinyu dengan warna solid, yang menutupi lapisan cat sebelumnya. Untuk contoh di atas, saya bisa melukis setengah kiri biru, setengah kanan merah, dan kemudian dua area hijau yang terpisah untuk total 4 langkah (hijau tidak terus-menerus dicat).

masukkan deskripsi gambar di sini

Ini dia di ASCII:

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

Ada beberapa cara berbeda untuk mengecat tongkat ini dan berakhir dengan hasil yang sama. Namun, saya hanya tertarik pada perkiraan waktu, yaitu empat langkah.

Tujuan

Program Anda harus menampilkan jumlah langkah minimum yang diperlukan untuk mengecat stik dengan skema warna tertentu. Skema cat akan berupa string karakter, sedangkan outputnya berupa angka. Ini golf kode. Kemenangan program terpendek.

Memasukkan

Program Anda akan menerima skema pewarnaan untuk tongkat dalam bentuk untaian huruf. Setiap huruf unik (peka huruf besar kecil) mewakili warna unik.

YRYGR

grG

GyRyGyG

pbgbrgrp

hyghgy

Keluaran

Angka-angka ini adalah jumlah langkah terkecil yang diperlukan untuk mengecat tongkat.

4

3

4

5

4

Penjelasan

Beginilah cara saya mencapai angka-angka di atas. Program Anda tidak perlu menampilkan ini:

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

 ---
 g--
 gr-
 grG

 -------
 GGGGGGG
 GyyyGGG
 GyRyGGG
 GyRyGyG

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

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

Sunting: Saya akan menambahkan lebih banyak kasus uji jika terbukti lebih sulit.

PhiNotPi
sumber
Ini mengingatkan saya pada stackoverflow.com/q/10364248/785745 , yang serupa, tetapi dalam 2D.
Kendall Frey

Jawaban:

3

GolfScript, 82 72 67 karakter

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

Cukup cepat untuk program GolfScript, contoh:

> hyghgy
4

> pbgbrgrp
5

Algoritma yang digunakan bekerja melalui warna dari kiri ke kanan secara rekursif, sesuai dengan pernyataan berikut:

  • Abaikan semua bagian dari kiri yang sudah memiliki warna yang diperlukan. Overpainting mereka lagi tidak akan memberikan jawaban yang lebih baik.
  • Jika stik lengkap sudah memiliki warna yang diinginkan, kembalikan 0 langkah sebagai hasilnya.
  • Jika tidak, ambil warna target dari bagian paling kiri sekarang (yaitu yang pertama tidak dalam warna yang diinginkan).

    • Cat 1 bagian dengan warna target dan perulangan.
    • Warnai 2 bagian dengan warna ini dan rekur ulang.

    ...

    • Cat seluruh tongkat yang tersisa dengan warna ini dan ulangi.

    Ambil minimum dari semua angka itu dan tambahkan 1 (untuk langkah saat ini). Kembalikan ini sebagai jumlah langkah optimal.

Algoritma ini berfungsi, karena bagian paling kiri harus dicat pada satu waktu, jadi mengapa tidak segera melakukannya - dengan cara apa pun yang mungkin.

.,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
Howard
sumber
+1 untuk algoritme "warna paling kiri salah". Namun, ini sepertinya n!langkah;) (tapi mungkin ini kompleksitas sebenarnya, saya tidak tahu).
yo '
2

JavaScript: 187 Bytes

Dengan asumsi kita diizinkan untuk hanya memiliki input dan output ke suatu fungsi (tolong)!

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 Bytes dengan melakukan optimasi jelek lebih lanjut (Yang merupakan bagian dari intinya, dan saya merasa sangat menyenangkan):

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 Bytes Saya menyadari bahwa panjang input adalah batas atas dan saya tidak perlu menangani kasus sepele secara terpisah sekarang.

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}

Kasus uji:

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

Versi yang diperluas:

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

Untuk setiap karakter input, hitung panjang pola jika kita mengecat warna itu terlebih dahulu. Ini dilakukan dengan berpura-pura kita mengecat warna itu dan kemudian membuat sub bagian dari bit-bit yang bukan warna itu, dan secara rekursif memanggil metode cat pada mereka. Jalur terpendek dikembalikan.

Contoh ( YRYGR):

Awalnya, coba R. Ini memberi kita sub kelompok Ydan YG. Ysecara sepele dicat dalam sekali jalan.

Untuk YG: Coba G, Ysepele, panjang 2. Coba Y, Gsepele, panjang 2. YGkarena itu panjang 2.

RKarena itu, melukis dulu memberi kita1 + 1 + 2 = 4

Lalu coba G. Ini memberi kita sub kelompok YRYdan R. Rsepele.

Untuk YRY:

Coba Y: Rsepele, panjang 2. Coba R: Ydan Ydua kelompok, panjangnya 3.

YRYpanjang 2.

Lukisan Gpertama memberi1 + 1 + 2 = 4

Lalu coba Y. Ini memberikan sub kelompok Rdan GR. Rsepele, GRpanjang 2. Ypanjang4

Implementasi ini kemudian akan memeriksa R dan Y lagi untuk mengurangi panjang kode. Karena itu hasilnya YRYGRadalah 4.

meiamsome
sumber
Saya pikir versi Anda yang diperluas kehilangan var di msuatu tempat.
Hasturkun
Sayangnya, versi Anda juga tidak memberikan hasil yang benar untuk input "abcacba".
Howard
@Asturkun mhanyalah singkatan untuk word.length:) @Howard Anda benar, saya harus memikirkan kembali ini.
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]))

Saya gunakan ?untuk menandai area yang mungkin warna apa pun. Dmemilih wilayah yang berdekatan dari tongkat yang hanya berisi satu warna (plus mungkin beberapa ?s), warna yang bertahan wilayah terakhir, menggantikan daerah itu dengan ?s, dan berulang untuk menemukan semua langkah sebelumnya.

Waktu berjalan eksponensial. Cukup cepat untuk melakukan contoh dalam waktu yang wajar (beberapa menit). Saya bertaruh dengan memoisasi itu bisa jauh lebih cepat.

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

Tampaknya berhasil, tetapi saya masih belum 100% yakin bahwa metode ini akan selalu menemukan jumlah langkah minimum.

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

Demo di JSFiddle.net

Versi tidak digabungkan termasuk kode debug dan komentar:

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
TimWolla
sumber
Tampaknya mengembalikan hasil yang salah untuk hyghgy. Dikatakan 5 tetapi harus 4. (namun, mengembalikan hasil yang benar dari 4 untuk hyghgyh).
PhiNotPi
@PhiNotPi Tuhan, ini mendorong saya kembali lebih dari 60 karakter :( Mencoba untuk menerapkan kembali ini dalam bahasa lain, setelah tidur siang.
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]]}

Ini mencoba semua kemungkinan penulisan ulang hingga panjang string, dan berlanjut sampai menemukan yang membangun pola input. Tak perlu dikatakan, waktu yang eksponensial (dan kemudian beberapa).

Nama samaran
sumber
0

Pencarian pertama yang luas dan sederhana. Itu tidak memasukkan apa pun pada antrian yang sudah terlihat. Ini bekerja di bawah satu detik untuk semua contoh tetapi 'pbgbrgrp' yang sebenarnya membutuhkan satu menit penuh :(

Sekarang saya memiliki sesuatu yang berfungsi, saya akan berusaha menemukan sesuatu yang lebih cepat dan lebih pendek.

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)
TrevorM
sumber
Bisakah Anda memeriksa lekukannya? Tampaknya rusak.
Howard
@ Bagaimana diperbaiki. Saya tidak tahu apa yang saya pikirkan tadi malam.
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]

Tes berjalan:

λ: p "YRYGR"
4

λ: p "grG"
3

λ: p "GyRyGyG"
4

λ: p "pbgbrgrp"
5

λ: p "hyghgy"
4

λ: p "abcacba"
4

Metode ini bahkan tidak terlalu efisien!

MtnViewMark
sumber