Problem:
Rubik Dungeon

Problem

あなたはn × n × nの立方体のルービックキューブ型のダンジョンにやってきた。

あなたは現在(x1,y1,z1)の部屋にいる。

目標の宝は(x2,y2,z2)の部屋にある。

あなたは隣接している前後左右上下の部屋に単位時間で移動することができる。

各部屋には6つのボタンがあり、それぞれのボタンを押すことにより、単位時間で、ルービックキューブのように以下の操作を行うことができる：

現在いる部屋とx座標の値が同じ全ての部屋を時計または反時計周りに90度回転することができる

現在いる部屋とy座標の値が同じ全ての部屋を時計または反時計周りに90度回転することができる

現在いる部屋とz座標の値が同じ全ての部屋を時計または反時計周りに90度回転することができる

回転している途中で他の部屋に移動することはできない。

宝のある部屋まで最短で移動した場合の時間を求めよ。

Input

n
x1 y1 z1
x2 y2 z2

入力は全て整数で与えられる。

1行目にnが与えられる。

2行目に現在地の座標(x1,y1,z1)、3行目に宝のある部屋の座標(x2,y2,z2)が空白区切りで与えられる。

Constraints

2 ≤ n ≤ 105

0 ≤ x1,y1,z1,x2,y2,z2 ≤ n−1

(x1,y1,z1) ≠ (x2,y2,z2)

Output

最短の時間を出力せよ。

Sample Input 1

3
0 0 0
1 2 2

Sample Output 1

3

Sample Input 2

3
0 0 0
0 0 2

Sample Output 2

2

回転させると宝も移動してしまうので、回転させずに移動する。

Solution in Scala (judge verdict: Runtime Error)

import scala.collection.mutable

object Main extends App {

  import scala.io.StdIn._
  import scala.math._

  Coordinate.size = readLine.trim.toInt - 1
  val Array(sx, sy, sz) = readLine.trim.split(' ').map(_.toInt)
  val Array(gx, gy, gz) = readLine.trim.split(' ').map(_.toInt)
  val start = Coordinate(sx, sy, sz)
  val goal = Coordinate(gx, gy, gz)

  val rotate: List[Coordinate ⇒ Option[Coordinate]] = List(
    c ⇒ if (c.x == goal.x) None else Some(c.rotateXForward),
    c ⇒ if (c.x == goal.x) None else Some(c.rotateXBackward),
    c ⇒ if (c.y == goal.y) None else Some(c.rotateYForward),
    c ⇒ if (c.y == goal.y) None else Some(c.rotateYBackward),
    c ⇒ if (c.z == goal.z) None else Some(c.rotateZForward),
    c ⇒ if (c.z == goal.z) None else Some(c.rotateZBackward))
  val shift: List[Coordinate ⇒ Option[Coordinate]] = List[Coordinate ⇒ Coordinate](
    _ + Coordinate(1, 0, 0),
    _ + Coordinate(-1, 0, 0),
    _ + Coordinate(0, 1, 0),
    _ + Coordinate(0, -1, 0),
    _ + Coordinate(0, 0, 1),
    _ + Coordinate(0, 0, -1)
  ).map{op ⇒ {c: Coordinate ⇒ op(c) match {
    case n@Coordinate(x, y, z) if List(x, y, z).forall(p ⇒ (0 until Coordinate.size).contains(p)) ⇒ Some(n)
    case _ ⇒ None
  }}}
  val shifts = Array.tabulate(3){_ ⇒ shift}.scanLeft((c ⇒ List(c)): Coordinate ⇒ List[Coordinate]){
    case (left, right) ⇒ c ⇒ left(c).flatMap(n ⇒ right.flatMap(op ⇒ op(n)))
  }
  println(
    shifts.indices.map{count ⇒ count + shifts(count)(start).map(c ⇒ calMin(c, goal)).min}.min
  )
  def calMin(start: Coordinate, goal: Coordinate): Int = {
    val map = mutable.Map[Coordinate, Int]((start, minCost(start, goal)))
    var current = List(start)
    var count = 0
    while (current.nonEmpty) {
      count += 1
      current = current.flatMap { c ⇒ rotate.flatMap { op ⇒ op(c) } }.filterNot { c ⇒
        if (map.contains(c)) true
        else {
          map(c) = minCost(c, goal) + count
          false: Boolean
        }
      }
    }
    map.values.min
  }
  def minCost(from: Coordinate, to: Coordinate): Int = {
    to - from match {
      case Coordinate(x, y, z) ⇒ math.abs(x) + math.abs(y) + math.abs(z)
    }
  }
  object Coordinate{
    var size: Int = 0
    private def origin: Coordinate2D = Coordinate2D(size, size)
  }
  case class Coordinate(x: Int, y: Int, z: Int) {
    def -(that: Coordinate): Coordinate = Coordinate(x - that.x, y - that.y, z - that.z)
    def +(that: Coordinate): Coordinate = Coordinate(x + that.x, y + that.y, z + that.z)
    def rotateXForward: Coordinate = (Coordinate2D(y * 2, z * 2) - Coordinate.origin).rotateRight.let{it ⇒
      it + Coordinate.origin match {
        case Coordinate2D(y2, z2) ⇒ Coordinate(x, y2 / 2, z2 / 2)
      }
    }
    def rotateXBackward: Coordinate = (Coordinate2D(y * 2, z * 2) - Coordinate.origin).rotateLeft.let{it ⇒ it + Coordinate.origin match {case Coordinate2D(y2, z2) ⇒ Coordinate(x, y2 / 2, z2 / 2)}}
    def rotateYForward: Coordinate = (Coordinate2D(x * 2, z * 2) - Coordinate.origin).rotateRight.let{it ⇒ it + Coordinate.origin match {case Coordinate2D(x2, z2) ⇒ Coordinate(x2 / 2, y, z2 / 2)}}
    def rotateYBackward: Coordinate = (Coordinate2D(x * 2, z * 2) - Coordinate.origin).rotateLeft.let{it ⇒ it + Coordinate.origin match {case Coordinate2D(x2, z2) ⇒ Coordinate(x2 / 2, y, z2 / 2)}}
    def rotateZForward: Coordinate = (Coordinate2D(x * 2, y * 2) - Coordinate.origin).rotateRight.let{it ⇒ it + Coordinate.origin match {case Coordinate2D(x2, y2) ⇒ Coordinate(x2 / 2, y2 / 2, z)}}
    def rotateZBackward: Coordinate = (Coordinate2D(x * 2, y * 2) - Coordinate.origin).rotateLeft.let{it ⇒ it + Coordinate.origin match {case Coordinate2D(x2, y2) ⇒ Coordinate(x2 / 2, y2 / 2, z)}}
  }
  case class Coordinate2D(x: Int, y: Int){
    def rotateRight = Coordinate2D(y, -x)
    def rotateLeft = Coordinate2D(-y, x)
    def -(that: Coordinate2D) = Coordinate2D(x - that.x, y - that.y)
    def +(that: Coordinate2D) = Coordinate2D(x + that.x, y + that.y)
  }
  implicit class Extension[T](val value :T){
    def also(func: T ⇒ Unit): T = {
      func(value)
      value
    }
    def let[R](func: T ⇒ R): R = func(value)
  }
}