Problem:
学食

今日はＺ大学のオープンキャンパスです。毎年この日の昼休みには、大勢の高校生たちが学食に列をつくります。そこでＺ大学の事務局は、行列の長さが最大でどのくらいの距離になるかを予測することにしました。事前調査の結果で、以下のことが分かっています。

行列にはそれぞれ 1 から N までの番号が振られた N 人が並びます。

C 個の高校生のペア (ai, bi) それぞれについて、以下の２種類の制約があります：

１つ目の制約は順序に関するもので以下のいずれかです：

ai は bi よりも先、または同じ位置に並ばなくてはならない

ai は bi よりも後、または同じ位置に並ばなくてはならない

ai は bi より先でも、同じ位置でも、後でもよい

２つ目の制約は距離に関するもので以下のいずれかです：

ai と bi は di メートル以上離れなければならない

ai と bi は di メートル以内に並ばなければならない

また、先頭から同じ距離の場所に複数の人が並ぶことができ、行列の先頭には常に番号 1 の人が並ぶことが分かっています。

与えられた C 個の制約をすべて満たす行列について、先頭から最後尾までの距離が最大となるような並び方をした場合の距離を求めるプログラムを作成してください。ただし、どこまでも離れることができる場合は inf と、制約を満たす並び方が不可能な場合は -1 と出力してください。

入力

入力は以下の形式で与えられる。

N C
constraint1
constraint2
:
constraintC

1 行目に行列に並ぶ高校生の人数 N (2 ≤ N ≤ 100) と制約の数 C (0 ≤ C ≤ 200) が与えられる。続く C 行に各制約 constrainti が次の形式で与えられる。

aioibisidi

制約には空白は含まれない。ai, oi, bi, si, di の意味を以下に示す。

ai と bi (1 ≤ ai, bi ≤ N かつ ai ≠ bi ) は高校生の番号、di は距離 (0 ≤ d ≤ 10000) を表す整数である。

oi は順序の制約を指定する <=、>=、* のいずれかの文字列であり、<= の場合「ai は bi よりも先、または同じ位置に並ばなくてはならない」、>= の場合「ai は bi よりも後、または同じ位置に並ばなくてはならない」、* の場合「ai は bi より先でも、同じ位置でも、後でもよい」ことを意味する。ただし oi が * となる制約は７個以上与えられることはない。

si は距離の制約を指定する + または - の文字であり、+ の場合「ai と bi は di メートル以上離れなければならない」、- の場合「ai と bi は di メートル以内に並ばなければならない」ことを意味する。

ただし、あるペアに対して複数の制約が与えられることはないものとする。

出力

先頭から最後尾までの距離を１行に出力する。

入出力例

入力例１

3 2
1<=2-1
2<=3-2

出力例１

3

入力例２

3 3
1<=2-1
2<=3-2
1<=3+4

出力例２

-1

入力例３

3 2
1<=2-2
2*3+1

出力例３

inf

Solution in Scala (judge verdict: Runtime Error)

object Main extends App {
  import scala.io.StdIn.readLine
  val Array(studentNum, constraintNum) = readLine().split(' ').map(_.toInt)
  implicit val students = Student(studentNum)
  for (_ ← 0 until constraintNum){
    parseConstraint(readLine().trim().toList)
  }
  println(searchMax(students) match{
    case Some(m) if m == Int.MaxValue ⇒ "inf"
    case Some(m) ⇒ m
    case _ ⇒ -1
  })
  def searchMax(student:Array[Student]):Option[Int] = {
    var max = 0
    var hasRoute = false
    val memo = Array.tabulate(student.size){_ ⇒ Int.MaxValue}
    memo(0) = 0
    for (selector ← Student.validSelectors){
      var count = 0
      var isRenew = true
      while (count <= student.size && isRenew) {
        isRenew = false
        for (s ← student) {
          if (memo(s.id - 1) != Int.MaxValue) {
            for (Relation(to, distance) ← s.Relations(selector)) {
              if (memo(to.id - 1) > memo(s.id - 1) + distance) {
                memo(to.id - 1) = memo(s.id - 1) + distance
                isRenew = true
              }
            }
          }
        }
        count += 1
      }
      if (count <= student.size) {
        hasRoute = true
        if (max < memo.max)
          max = memo.max
      }
      memo.indices.foreach(memo(_) = Int.MaxValue)
      memo(0) = 0
    }
    if (hasRoute) Some(max)
    else None
  }
  def parseConstraint(str:List[Char])(implicit students:Array[Student]):Unit = {
    str match{
      case (a FasterThan b) & NearThan(d) ⇒
        Student.FasterAndNear(students(a - 1), students(b - 1), d)
      case (a FasterThan b) & FarThan(d) ⇒
        Student.FasterAndFar(students(a - 1), students(b - 1), d)
      case (a LaterThan b) & NearThan(d) ⇒
        Student.LaterAndNear(students(a - 1), students(b - 1), d)
      case (a LaterThan b) & FarThan(d) ⇒
        Student.LaterAndFar(students(a - 1), students(b - 1), d)
      case (a NoOrder b) & NearThan(d) ⇒
        Student.NoOrderAndNear(students(a - 1), students(b - 1), d)
      case (a NoOrder b) & FarThan(d) ⇒
        Student.NoOrderAndFar(students(a - 1), students(b - 1), d)
      case _ ⇒ ???
    }
  }
}
class Student private (val id:Int){
  private var mRelation:List[Relation] = Nil
  private var mSelectableRelation:List[Int ⇒ Option[Relation]] = Nil
  private def addRelation(to:Student, distance:Int):Unit = {
    mRelation ::= Relation(to, distance)
  }
  private def addSelectableRelation(selector:Int ⇒ Boolean, to:Student, distance:Int):Unit = {
    val relation = Some(Relation(to, distance))
    mSelectableRelation ::= {n:Int ⇒ if (selector(n)) relation else None}
  }
  def Relations(implicit selector:Int):List[Relation] = mSelectableRelation.flatMap{f ⇒ f(selector)} ++ mRelation
}
object Student{
  private var noOrderConstrain:Int = 0
  def FasterAndNear(a:Student, b:Student, d:Int): Unit = {
    a.addRelation(b, d)
    b.addRelation(a, 0)
  }
  def FasterAndFar(a:Student, b:Student, d:Int):Unit = {
    b.addRelation(a, -d)
  }
  def LaterAndNear(a:Student, b:Student, d:Int):Unit = {
    a.addRelation(b, 0)
    b.addRelation(a, d)
  }
  def LaterAndFar(a:Student, b:Student, d:Int):Unit = {
    a.addRelation(b, -d)
  }
  def NoOrderAndNear(a:Student, b:Student, d:Int):Unit = {
    val current = noOrderConstrain
    a.addSelectableRelation({n ⇒ (n & (1 << current)) != 0}, b, d)
    b.addSelectableRelation({n ⇒ (n & (1 << current)) == 0}, a, d)
    noOrderConstrain += 1
  }
  def NoOrderAndFar(a:Student, b:Student, d:Int):Unit = {
    val current = noOrderConstrain
    a.addSelectableRelation({n ⇒ (n & (1 << current)) != 0}, b, d)
    b.addSelectableRelation({n ⇒ (n & (1 << current)) == 0}, a, d)
    noOrderConstrain += 1
  }
  def apply(size:Int):Array[Student] = {
    val res = Array.tabulate(size){n ⇒ new Student(n + 1)}
    for (i ← 1 until size){
      res(i).addRelation(res(0), 0)
    }
    res
  }
  def validSelectors:Range = 0 until (1 << noOrderConstrain)
}
case class Relation(otherStudent:Student, distance:Int)
object Id{
  def unapply(arg: List[Char]): Option[(Int, List[Char])] = arg match{
    case n Digits r ⇒ Some(n.mkString.toInt, r)
    case _ ⇒ None
  }
  private object Digits{
    def unapply(arg: List[Char]): Option[(List[Char], List[Char])] = arg  match{
      case h::t if h.isDigit ⇒
        t match{
          case n Digits r ⇒ Some(h::n, r)
          case _ ⇒ Some(List(h), t)
        }
      case _ ⇒ None
    }
  }
}
object Number{
  def unapply(arg: List[Char]): Option[(Int, List[Char])] = arg match{
    case n Id r ⇒ Some(n, r)
    case _ ⇒ None
  }
}
object FasterThan{
  def unapply(arg: List[Char]): Option[(Int, Int)] = arg match{
    case a Id '<'::'='::(b Id _)⇒ Some(a, b)
    case _ ⇒ None
  }
}
object LaterThan{
  def unapply(arg: List[Char]):Option[(Int, Int)] = arg match{
    case a Id '<'::'='::(b Id _) ⇒ Some(a, b)
    case _ ⇒ None
  }
}
object NoOrder{
  def unapply(arg: List[Char]): Option[(Int, Int)] = arg match{
    case a Id '*'::(b Id _) ⇒ Some(a, b)
    case _ ⇒ None
  }
}
object NearThan{
  def unapply(arg:List[Char]):Option[Int] = arg match {
    case '-'::(n Number _) ⇒ Some(n)
    case _::t ⇒ unapply(t)
    case Nil ⇒ None
  }
}
object FarThan{
  def unapply(arg: List[Char]): Option[Int] = arg match{
    case '+'::(n Number _) ⇒ Some(n)
    case _::t ⇒ unapply(t)
    case _ ⇒ None
  }
}
object &{
  def unapply[T](arg: T): Option[(T, T)] = Some(arg, arg)
}