Problem:
連鎖

問題

次のようなゲームがある．

あるキャラクターが縦 1 列に N 個並んでいる．これらのキャラクターの色は赤，青，黄のいずれかであり，初期状態で同じ色のキャラクターが4つ以上連続して並んでいることはない．プレーヤーは，ある位置のキャラクターを選び他の色に変更することができる．この操作により同じ色のキャラクターが4つ以上連続して並ぶとそれらのキャラクターは消滅する．キャラクターが消滅することにより新たに同じ色のキャラクターが4つ以上連続して並ぶとそれらのキャラクターも消滅し，同じ色のキャラクターが4つ以上連続して並んでいる箇所がなくなるまでこの連鎖は続く．このゲームの目的は，消滅しないで残っているキャラクター数をなるべく少なくすることである．

例えば，下図の左端の状態で，上から6番目のキャラクターの色を黄色から青に変更すると，青のキャラクターが5つ連続するので消滅し，最終的に3つのキャラクターが消滅せずに残る．

初期状態における N 個のキャラクターの色の並びが与えられたとき， 1箇所だけキャラクターの色を変更した場合の，消滅しないで残っているキャラクター数の最小値 M を求めるプログラムを作成せよ．

入力

入力は複数のデータセットからなる．各データセットは以下の形式で与えられる．

1行目はキャラクター数 N (1 ≤ N ≤ 10000) だけからなる．続く N 行には 1, 2, 3 のいずれか1つの整数が書かれており， i + 1 行目 (1 ≤ i ≤ N) は初期状態における上から i 番目のキャラクターの色を表す（1 は赤を，2 は青を，3は黄を表す）．

N が 0 のとき入力の終了を示す．データセットの数は 5 を超えない．

出力

データセットごとに, 消滅しないで残っているキャラクター数の最小値 M を１行に出力せよ．

入出力例

入力例

12
3
2
1
1
2
3
2
2
2
1
1
3
12
3
2
1
1
2
3
2
1
3
2
1
3
0

出力例

3
12

上記問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。

Solution in Scala (judge verdict: Accepted)

import scala.annotation.tailrec

object Main extends App {

  import scala.io.StdIn._
  f

  def f: Unit = {
    val n = readLine.trim.toInt
    if (n == 0) return
    val num = toCh(List.tabulate(n){ _ ⇒ readLine.trim.toInt})
    println(n - search(num))
    f
  }
  def search(list: List[Ch]): Int = {
    def sub(prev: List[Ch], current: Ch, post: List[Ch], max: Int = 0): Int = {
      prev match {
        case c::t ⇒ sub(t, c, current::post, List(max, changeFirst(prev, current, post), changeLast(prev, current, post)).max)
        case _ ⇒ List(max, changeFirst(prev, current, post), changeLast(prev, current, post)).max
      }
    }
    list match {
      case Nil ⇒ 0
      case h::t ⇒ sub(t, h, Nil)
    }
  }
  def changeFirst(prev: List[Ch], current: Ch, post: List[Ch]): Int = {
    (prev, current, post) match {
      case (Ch(a, n)::t, Ch(_, 1), Ch(b, m)::u) if a == b && n + m >= 3 ⇒ n + m + 1 + remove(t, u)
      case (Ch(_, n)::t, Ch(a, m), _) if n >= 3 ⇒ if (m == 1) n + 1 + remove(t, post) else n + 1 + remove(t, Ch(a, m - 1)::post)
      case _ ⇒ 0
    }
  }
  def changeLast(prev: List[Ch], current: Ch, post: List[Ch]): Int = {
    (prev, current, post) match {
      case (Ch(a, n)::t, Ch(_, 1), Ch(b, m)::u) if a == b && n + m >= 3 ⇒ n + m + 1 + remove(t, u)
      case (_, Ch(a, n), Ch(_, m)::t) if m >= 3 ⇒ if (n == 1) m + 1 + remove(prev, t) else m + 1 + remove(Ch(a, n - 1)::prev, t)
      case _ ⇒ 0
    }
  }
  def remove(prev: List[Ch], post: List[Ch]): Int = {
    (prev, post) match {
      case (Ch(a, n)::t, Ch(b, m)::u) if a == b && n + m >= 4 ⇒ n + m + remove(t, u)
      case _ ⇒ 0
    }
  }
  @tailrec
  def toCh(list:List[Int], res: List[Ch] = Nil): List[Ch] = {
    list match {
      case Nil ⇒ res
      case h::t ⇒ res match {
        case Nil ⇒ toCh(t, Ch(h, 1)::res)
        case Ch(c, n)::rt if c == h ⇒ toCh(t, Ch(c, n + 1)::rt)
        case _ ⇒ toCh(t, Ch(h, 1)::res)
      }
    }
  }
  case class Ch(color: Int, num: Int)
}