Problem:
Problem J: Demon's Plan

BackGround

デーモンズプランでは慾を司る108体の悪魔が日夜プログラミングコンテストでしのぎを削っている。主催であるパトローンは、全ての慾が集う場所”リクス＝マグナ”に悪魔たちを招待しようとしている。
パトローンはまだ招待を送っていない悪魔に招待を送りたいが、悪魔は世界各地におり、自分で行くのは面倒くさいので自身の使い魔達にやらせることにした。
パトローンは気が利くので使い魔同士がより平等に働くようにどの使い魔がどの悪魔を担当するかを割り振ろうとしている。

Problem

N体の使い魔とM体の悪魔がいる。
使い魔i と 悪魔j の距離は Hi jである。

各悪魔に必ず1人の使い魔を向かわせたい。どの使い魔がどの悪魔を訪問するかは以下の条件に従って割り振ることにした。

使い魔1体あたりの訪問する悪魔の数の差の最大を最小化する。

1を満たした上で訪問する悪魔と担当する使い魔の距離の最大を最小化する。

1行目に使い魔1体あたりの訪問する悪魔の数の差の最大を、2行目に悪魔と担当する使い魔の距離の最大を出力せよ。

Input

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

N M
H0 0 H0 1 … H0 M−1
H1 0 H1 1 … H1 M−1
.
.
HN−1 0 HN−1 1 … HN−1 M−1

1行目に使い魔の数Nと悪魔の数Mが整数で空白区切りで与えられる。
続くN行に使い魔と悪魔の距離が整数で与えられる。Hijは使い魔iと悪魔jの距離を表す。

Constraints

1 ≤ N ≤ 108

1 ≤ M ≤ 108

1 ≤ Hi j ≤ 109 ( 0 ≤ i < N, 0 ≤ j < M ) ( 使い魔iから悪魔jまでの距離 )

Output

問題文の条件に従い、1行目に使い魔1体あたりの訪問する悪魔の数の差の最大を、2行目に悪魔と担当する使い魔の距離の最大を出力せよ。

Sample Input 1

3 3
1 2 3
2 1 2
3 2 1

Sample Output 1

0
1

使い魔0 - 悪魔0

使い魔1 - 悪魔1

使い魔2 - 悪魔2

と割り振ることで訪問する悪魔の数の差が0になり、担当使い魔と悪魔の距離の最大が1になり最適な組み合わせになる。

Sample Input 2

3 5
1 2 3 4 5
5 4 3 2 1
4 3 2 1 5

Sample Output 2

1
2

使い魔0 - 悪魔0

使い魔0 - 悪魔1

使い魔1 - 悪魔4

使い魔2 - 悪魔3

使い魔2 - 悪魔2

と割り振ることで訪問する悪魔の差が1になり、担当使い魔と悪魔の距離の最大が2になり最適な組み合わせになる。

Solution in Scala (judge verdict: Accepted)

import scala.collection.mutable
import scala.io.StdIn._
object Main extends App {
  val Array(n, m) = readLine.trim.split(' ').map(_.toInt)
  val distance = Array.tabulate(n){_ ⇒ readLine.trim.split(' ').map(_.toLong)}
  var left = 1L
  var right = distance.map{_.max}.max
  while(left < right) {
    val mid = (left + right) / 2
    if (pushFlow(makeGraph(distance, mid)) == m) right = mid
    else left = mid + 1
  }
  println(if (m % n == 0) 0 else 1)
  println(right)
  def makeGraph(distance: Array[Array[Long]], maxDistance: Long): Array[List[Edge]] = {
    val smaller = m / n
    val rest = m % n
    val sourceForSmaller = n * 2 + m
    val sourceForRest = sourceForSmaller + 1
    val source = sourceForRest + 1
    val sink = source + 1
    val result = Array.fill(sink + 1){Nil: List[Edge]}
    def setEdge(from: Int, to: Int, flow: Int): Unit = {
      result(from) ::= Edge(to, flow)
      result(to) ::= Edge(from, 0)
      result(from).head.pair = result(to).head
      result(to).head.pair = result(from).head
    }
    for (i ← 0 until n) {
      setEdge(sourceForSmaller, i, smaller)
      setEdge(sourceForRest, i + n, 1)
      for (j ← 0 until m if distance(i)(j) <= maxDistance){
        setEdge(i, 2 * n + j, 1)
        setEdge(i + n, 2 * n + j, 1)
      }
    }
    for (j ← 0 until m) {
      setEdge(2 * n + j, sink, 1)
    }
    setEdge(source, sourceForSmaller, smaller * n)
    setEdge(source, sourceForRest, rest)
    result
  }
  def pushFlow(nodes: Array[List[Edge]]): Int = {
    val source = nodes.length - 2
    val sink = nodes.length - 1
    val depth = Array.fill(nodes.length){-1}
    val searching = Array.tabulate(nodes.length)(nodes)
    def bfs() = {
      depth.indices.foreach(i ⇒ depth(i) = -1)
      searching.indices.foreach(i ⇒ searching(i) = nodes(i))
      val queue = mutable.Queue[Int](source)
      depth(source) = 0
      while(queue.nonEmpty) {
        val current = queue.dequeue()
        if (current != sink) for (Edge(to, flow) ← nodes(current) if flow > 0 && depth(to) == -1) {
          depth(to) = depth(current) + 1
          queue.enqueue(to)
        }
      }
    }
    def dfs(current: Int): Boolean = {
      if (current == sink) true
      else {
        var result = false
        while (!result && searching(current).nonEmpty) {
          searching(current) match {
            case (e@Edge(to, flow))::rest if flow > 0 && depth(to) > depth(current) ⇒
              result = dfs(to)
              if (result) {
                e.flow -= 1
                e.pair.flow += 1
              }else searching(current) = rest
            case _::rest ⇒
              searching(current) = rest
            case _ ⇒
          }
        }
        result
      }
    }
    var count = 0
    var hasFlow = true
    while(hasFlow) {
      hasFlow = false
      bfs()
      while(dfs(source)) {
        count += 1
        hasFlow = true
      }
    }
    count
  }
}
case class Edge(to: Int, var flow: Int) {
  private var mPair = this
  def pair: Edge = mPair
  def pair_=(edge: Edge) = mPair = edge
}