Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

あみだくじ

PCK 君はみんなでゲーム大会をしています。このゲーム大会では、大会の最後にあみだくじで順位を入れ替えます。大会には N 人のプレイヤーが参加しており、あみだくじには N 本の縦棒があります。

あみだくじは、図のように N - 1 段の部品からできており、それぞれ 1 から N-1 の番号が割り当てられています。各部品は、あみだくじの一部を横方向に切り取った部分です。各部品にはいくつかの横棒が引かれていますが、部品の中の横棒はすべて同じ高さにあります。横棒同士がつながることはありません。

大会の最後に、順位の高い人から右から左の順に縦棒が割り当てられます。PCK 君は現時点で最下位なので、左端からスタートです。例えば、上図の組み立て方では、６位だったPCK 君は、このあみだくじによって４位（右から４番目の棒）に浮上することができます。

このゲームでは、最下位の人にあみだくじを組み立てる権利が与えられます。PCK 君はうまくあみだくじの部品の順番を決めて、逆転優勝を狙っています。ただし、部品を回転することはできません。

（※補足：あみだくじのたどり方について）

あみだくじのある縦棒の上端から出発して上から下へ進む。ただし、横棒がある地点ではその横棒でつながった別の縦棒に移動する。これを、縦棒の下端にたどり着くまで繰り返す。

ゲームの参加人数とあみだくじの部品の情報を入力し、PCK 君が優勝できるかどうか判定するプログラムを作成せよ。優勝できる場合、そのあみだくじの部品の並びを１つ出力せよ。ただし、そのような並べ方が複数ある場合は、与えられた部品の番号で辞書順最小のものを出力せよ。

Input

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

N
b1,1 b1,2 ... b1,N−1
b2,1 b2,2 ... b2,N−1
:
bN−1,1 bN−1,2 ... bN−1,N−1

１行目に大会の参加者数 N (2 ≤ N ≤ 500) が与えられる。続く N-1 行に i 番目の部品の横棒の情報が与えられる。bi,j が 1 であるとき、i 番目の部品の、左から j 本目の縦棒から j+1 番目の縦棒へ横棒が引かれていることを表す。bi,j が 0 であるとき、i 番目の部品の、左から j 本目の縦棒から j+1 番目の縦棒へ横棒は引かれていないことを表す。bi,j が 1 であるとき、bi,j+1 が 1 となるような部品は与えられない。また、横棒の総数は 10000 を越えない。

Output

PCK 君が優勝できる場合，１行目に「yes」と出力する。続く N-1 行に、あみだくじの上から順に、部品の番号の並びを出力する。そのような並びが複数ある場合、辞書順最小である並びを出力する。PCK 君が優勝できない場合、１行に「no」と出力する。

Sample Input 1

6
1 0 0 0 1
1 0 1 0 1
0 1 0 1 0
0 0 0 1 0
0 1 0 0 1

Sample Output 1

yes
1
3
2
4
5

Sample Input 2

5
0 1 0 1
0 1 0 1
1 0 1 0
1 0 0 1

Sample Output 2

yes
4
1
3
2

4 1 3 2 と 4 2 3 1 の２通りの組み立て方が可能だが、辞書順で小さい方の 4 1 3 2 を出力する。

Sample Input 3

5
1 0 0 1
0 1 0 1
1 0 0 0
0 1 0 1

Sample Output 3

no

Solution in Scala (judge verdict: Accepted)

import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer

object Main extends App {

  import scala.io.StdIn._
  implicit class Extend[T](value: T){
    def let[R](func: T ⇒ R): R = func(value)
    def also(func: T ⇒ Unit): T = {func(value); value}
  }
  val n = readLine.trim.toInt
  val edges = makeGraph(n - 1, n - 1, Array.tabulate(n - 1){_ ⇒ readLine.trim.split(' ').map(_ == "1")}.let{arr ⇒ arr.indices.flatMap(f ⇒ arr(f).indices.collect{case t if arr(f)(t) ⇒ (t, f)}).toArray})
  val levels = Array.tabulate(n * 2){_ ⇒ -1}
  val dfsLast = Array.tabulate(n * 2){_ ⇒ 0}

  var matchingCount = 0
  var canMatch = true
  while (canMatch){
    canMatch = false
    bfs
    if (levels.last != -1) {
      canMatch = true
      while (dfs(0)) {
        matchingCount += 1
      }
    }
  }

  if (matchingCount == n - 1) {
    var matchingEdge = Nil:List[Int]
    for (x ← 1 until n){
      resetPath(x)
      levels.indices.foreach(i ⇒ levels(i) = -1)
      simpleDfs(0)
      matchingEdge ::= findMatching(x) - n + 1
      confirmMatching(x)
    }
    println("yes")
    println(matchingEdge.reverse.mkString("\n"))
  }else {
    println("no")
  }
  def findMatching(x: Int): Int = {
    edges(x).find(_._3 == false) match {
      case Some((to, _, _)) ⇒
        to
      case None ⇒ ???
    }
  }
  def confirmMatching(x: Int): Unit = {
    edges(x)(0) match {
      case (0, l, _) ⇒ edges(0)(l) = (x, 0, false)
      case _ ⇒ ???
    }
    edges(x).find(_._3 == false) match {
      case Some((y, l, _)) ⇒ edges(y)(l) = edges(y)(l).copy(_3 = false)
      case None ⇒ ???
    }

  }
  def resetPath(x: Int): Unit = {
    edges(x).indexWhere(_._3 == false) match {
      case i ⇒
        val (y, l, _) = edges(x)(i)
        edges(0)(edges(x)(0)._2) = edges(0)(edges(x)(0)._2).copy(_3 = true)
        edges(x)(i) = edges(x)(i).copy(_3 = true)
        edges(y)(l) = edges(y)(l).copy(_3 = false)
        edges(y)(0) = edges(y)(0).copy(_3 = true)
    }
  }
  def bfs: Unit = {
    dfsLast.indices.foreach(i ⇒ dfsLast(i) = 0)
    levels.indices.foreach(i ⇒ levels(i) = -1)
    levels(0) = 0
    val queue : mutable.Queue[Int]= mutable.Queue()
    queue.enqueue(0)
    while(queue.nonEmpty){
      val top = queue.dequeue()
      for ((to, _, b) ← edges(top) if b && levels(to) == -1) {
        levels(to) = levels(top) + 1
        queue.enqueue(to)
      }
    }
  }
  def simpleDfs(from: Int): Boolean = {
    if (from == n * 2 - 1) true
    else if (levels(from) != -1) false
    else {
      levels(from) = 0
      edges(from).zipWithIndex.find{case (it, _) ⇒ it._3 && simpleDfs(it._1)} match {
        case Some(((to, l, _), idx)) ⇒
          edges(from)(idx) = edges(from)(idx).copy(_3 = false)
          edges(to)(l) = edges(to)(l).copy(_3 = true)
          true
        case None ⇒ false
      }
    }
  }
  def dfs(from: Int): Boolean= {
    if (from == n * 2 - 1) true
    else {
      var makePath = false
      for (i ← dfsLast(from) until edges(from).length if  !makePath && edges(from)(i)._3) {
        if (levels(edges(from)(i)._1) > levels(from) && dfs(edges(from)(i)._1)) {
          val (to, j, _) = edges(from)(i)
          edges(from)(i) = (to, j, false)
          edges(to)(j) = (from, i, true)
          makePath = true
          dfsLast(from) = i + 1
        }
      }
      makePath
    }
  }

  def makeGraph(s: Int, t: Int, edge: Array[(Int, Int)]): Array[Array[(Int, Int, Boolean)]] = {
    val edges = Array.tabulate(s + t + 2){_ ⇒ ArrayBuffer[(Int, Int, Boolean)]()}
    for (x ← (1 to s).reverse){
      edges(x).append((0, edges(0).length, false))
      edges(0).append((x, 0, true))
    }
    for (y ← (s + 1) to s + t){
      edges(y).append((s + t + 1, edges(s + t + 1).length, true))
      edges(s + t + 1).append((y, 0, false))
    }
    for ((from, to) ← edge){
      edges(from + 1).append((to + s + 1, edges(to + s + 1).length, true))
      edges(to + s + 1).append((from + 1, edges(from + 1).length - 1, false))
    }
    edges.map{_.toArray}
  }
}