import scala.annotation.tailrec
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
import scala.reflect.ClassTag

object Main extends App {

  import scala.io.StdIn._
  solve
  def solve: Unit = {
    val Array(n, m, s, t) = readLine.trim.split(' ').map(_.toInt)
    if (n == 0) return
    val edges = Array.tabulate(m){_ ⇒
      val Array(a, b) = readLine.trim.split(' ').map(_.toInt - 1)
      (a, b)
    }
    val (flow, graph) = maxFlowWithUniCapacityEdge(s - 1, t - 1, n, edges)
    //sからのパスがあれば1、tからのパスがあれば-1
    val sortedGraph = graph.sorted(Ordering.fromLessThan[(Int, Int)]{case ((a, b), (c, d)) ⇒ if (a == c) b < d else a < c})
    val memo = Array.tabulate(n){_ ⇒ 0}
    val nodes = Array.tabulate(n){_ ⇒ ArrayBuffer[Int]()}.let{n ⇒
      for ((from, to) ← graph){
        n(from).append(to)
      }
      n.map{_.toArray}
    }
    val revNodes = Array.tabulate(n){_ ⇒ ArrayBuffer[Int]()}.let{n ⇒
      for ((from, to) ← graph){
        n(to).append(from)
      }
      n.map{_.toArray}
    }
    searchPath(revNodes, memo, t - 1, -1)
    searchPath(nodes, memo, s - 1, 1)
    val initEdge = edges.filter{
      case p ⇒
        val i = lowerBound(sortedGraph, p)
        if (i < sortedGraph.length) sortedGraph(i) == p
        else false
    }
    val count = initEdge.count{case (from, to) ⇒ memo(from) == -1 && memo(to) == 1}
    if (count == 0) println(s"$flow $count")
    else println(s"${flow + 1} $count")
    solve
  }

  def searchPath(graph: Array[Array[Int]], memo: Array[Int], from: Int, marker: Int): Unit = {
    val queue = mutable.Queue[Int](from)
    memo(from) = marker
    while (queue.nonEmpty){
      for (to ← graph(queue.dequeue()) if memo(to) != marker){
        memo(to) = marker
        queue.enqueue(to)
      }
    }
  }
  def lowerBound(array: Array[(Int, Int)], target: (Int, Int)): Int = {
    var left = 0
    var right = array.length
    while (left < right){
      val mid = (left + right) / 2
      if (array(mid)._1 < target._1 || (array(mid)._1 == target._1 && array(mid)._2 < target._2)) {
        left = mid + 1
      }else {
        right = mid
      }
    }
    right
  }
  implicit class Extend[T](value: T){
    def let[R](func: T ⇒ R): R = func(value)
    def also(func: T ⇒ Unit): T = {func(value); value}
  }
  def maxFlowWithUniCapacityEdge(source: Int, drain: Int, size: Int, edges: Array[(Int, Int)]): (Int, Array[(Int, Int)]) = {
    val nodes = makeGraph(size, edges)
    val levels = Array.tabulate(size){_ ⇒ -1}
    val searching = Array.tabulate(size){_ => 0}
    def bfs = {
      searching.indices.foreach(i ⇒ searching(i) = 0)
      levels.indices.foreach(i ⇒ levels(i) = -1)
      levels(source) = 0
      val queue = mutable.Queue[Int](source)
      while (queue.nonEmpty){
        val prev = queue.dequeue()
        for (Edge(to, _, b) ← nodes(prev) if b && levels(to) == -1){
          levels(to) = levels(prev) + 1
          queue.enqueue(to)
        }
      }
    }
    def dfs(from: Int): Boolean = {
      if (from == drain) true
      else {
        (searching(from) until nodes(from).length).find{i ⇒
          nodes(from)(i).flow && levels(from) < levels(nodes(from)(i).to) && dfs(nodes(from)(i).to)
        } match {
          case Some(i) ⇒
            searching(from) = i + 1
            val Edge(to, pair, _) = nodes(from)(i)
            nodes(to)(pair) = nodes(to)(pair).copy(flow = true)
            nodes(from)(i) = Edge(to, pair, false)
            true
          case None ⇒
            searching(from) = nodes(from).length
            false
        }
      }
    }
    var count = 0
    var matching = true
    while (matching){
      bfs
      matching = levels(drain) != -1
      if (matching){
        while(dfs(source)){count += 1}
      }
    }
    (count, nodes.indices.flatMap{from ⇒ nodes(from).withFilter(_.flow).map{e ⇒ (from, e.to)}}.toArray)
  }
  private case class Edge(to: Int, pair: Int, flow: Boolean)
  private def makeGraph(size: Int, edges: Array[(Int, Int)]): Array[Array[Edge]] = {
    val result = Array.tabulate(size){_ ⇒ ArrayBuffer[Edge]()}
    for ((from, to) ← edges){
      result(from).append(Edge(to, result(to).length, true))
      result(to).append(Edge(from, result(from).length - 1, false))
    }
    result.map(_.toArray)
  }
}
