Problem:
Reflection Warp Machine

Problem

とある宇宙では、2次元の格子点上にn個の星が存在し、宇宙人達はReflection Warp Machineを使い、星間を移動している。

この装置は、任意の位置、角度で直線を引くことができる。

この直線を対称軸として、現在いる座標から線対称の座標に移動することができる。

ただし、星が存在しない座標に移動することはできない。

一度引いた直線は何度でも利用できる。

現在、(x0,y0)の星にいるある宇宙人はすべての星を訪れたいと考えている。

星は好きな順番に訪れることができる。

すべての星を訪れるのに最小で何本の直線を引く必要があるか求めよ。

Input

n
x0 y0
...
xn−1 yn−1

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

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

2行目以降n行にi番目の星の座標(xi,yi)が空白区切りで与えられる。

Constraints

2 ≤ n ≤ 8

−100 ≤ xi,yi ≤ 100

(xi,yi) ≠ (xj,yj) (i ≠ j)

Output

すべての星を訪れるために必要な最小の直線の数を1行に出力せよ。

Sample Input 1

3
0 0
0 1
1 0

Sample Output 1

2

Sample Input 2

4
0 0
0 1
0 2
0 3

Sample Output 2

2

Solution in Scala (judge verdict: Wrong Answer)

object Main extends App {

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

  val n = readLine.trim.toInt
  val planets = Array.tabulate(n){_ ⇒
    val Array(x, y) = readLine.trim.split(' ').map(_.toInt.toRational)
    Coordinate(x, y)
  }
  println(
    planets.tail.permutations.map{p ⇒ minLine(p.toList, planets.head)}.min
  )
  def minLine(planets: List[Coordinate], start: Coordinate): Int = {
    def sub(planets: List[Coordinate], current: Coordinate, lines: List[Line]): Int = {
      planets match {
        case Nil ⇒ lines.length
        case h::t ⇒
          val line = verticalHalf(current, h)
          if (lines.contains(line)) sub(t, h, lines)
          else sub(t, h, line::lines)
      }
    }
    planets match {
      case h::t ⇒ sub(t, h, Nil)
      case _ ⇒ ???
    }
  }

  def verticalHalf(a: Coordinate, b: Coordinate): Line = {
    val mid = a + b match {case Coordinate(x, y) ⇒ Coordinate(x / 2.toRational, y / 2.toRational)}
    val diff = a - b  match {case Coordinate(x, y) ⇒ Coordinate(-y, x)}
    new Line(mid, mid + diff)
  }
  class Line(private val from: Coordinate, private val to: Coordinate){
    private def dx: Rational = (to - from).x
    private def dy: Rational = (to - from).y
    private def isOnLine(point: Coordinate): Boolean = {
      point - from match {
        case Coordinate(x, y) ⇒ dx * y == dy * x
      }
    }
    override def equals(obj: Any): Boolean = {
      obj match {
        case line: Line ⇒ isOnLine(line.from) && isOnLine(line.to)
        case _ ⇒ super.equals(obj)
      }
    }
  }
  object Rational{
    def apply(numerator: Long, denominator: Long): Rational = {
      val g = gcd(math.abs(numerator), math.abs(denominator))
      val signum = numerator.signum * denominator.signum
      new Rational(signum * math.abs(numerator / g), math.abs(denominator / g))
    }
    private def gcd(a: Long, b: Long): Long = {
      b match {
        case 0l ⇒ a
        case _ ⇒ gcd(b, a % b)
      }
    }
  }
  implicit class ToRational(val value: Int){
    def toRational: Rational = Rational(value, 1)
  }
  class Rational private (private val numerator: Long, private val denominator: Long) extends Ordered[Rational] {
    def +(that: Rational): Rational = Rational(numerator * that.denominator + denominator * that.numerator, denominator * that.denominator)
    def -(that: Rational): Rational = Rational(numerator * that.denominator - denominator * that.numerator, denominator * that.denominator)
    def *(that: Rational): Rational = Rational(numerator * that.numerator, denominator * that.denominator)
    def /(that: Rational): Rational = Rational(numerator * that.denominator, denominator * that.numerator)
    def unary_-(): Rational = Rational(-numerator, denominator)
    override def compare(that: Rational): Int = (this - that).numerator.compare(0)
  }
  case class Coordinate(x: Rational, y: Rational){
    def -(that: Coordinate): Coordinate = Coordinate(x - that.x, y - that.y)
    def +(that: Coordinate): Coordinate = Coordinate(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)
  }
}