#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <cfloat>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <iostream>
#include <set>
#include <map>
#include <time.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 1005

enum Type{
	FROM_S,
	FROM_T,
};


//辺を表す構造体(行先、容量、逆辺のインデックス)
struct Edge{
	Edge(int arg_to,int arg_capacity,int arg_rev_index,bool arg_is_rev){
		to = arg_to;
		capacity = arg_capacity;
		rev_index = arg_rev_index;
		is_rev = arg_is_rev;
	}
	int to,capacity,rev_index;
	bool is_rev;
};

int V,E;
int N,M,S,T;

vector<Edge> G[NUM]; //グラフの隣接リスト表現
bool used[NUM]; //DFSですでに調べたかのフラグ
bool can_reach[2][NUM]; //S,Tから各点へ到達できるかのチェック

//fromからtoへ向かう容量capacityの辺をグラフに追加する
void add_edge(int from,int to,int capacity){
	G[from].push_back(Edge(to,capacity,G[to].size(),false));
	G[to].push_back(Edge(from,0,G[from].size()-1,true)); //逆辺の、初期容量は0
}

//増加パスをDFSで探す
int dfs(int node_id,int sink,int flow){
	if(node_id == sink)return flow; //終点についたらflowをreturn
	used[node_id] = true;

	for(int i = 0; i < G[node_id].size(); i++){ //node_idから出ているエッジを調査
		Edge &e = G[node_id][i];
		if(used[e.to] == false && e.capacity > 0){ //エッジの先のノードに未訪問で、かつエッジに流す余裕がある場合
			int tmp_flow = dfs(e.to,sink,min(flow,e.capacity)); //流せるだけ流す
			if(tmp_flow > 0){ //流せた場合
				e.capacity -= tmp_flow; //流した分、エッジの容量を削減する
				G[e.to][e.rev_index].capacity += tmp_flow; //逆辺の容量を、流した分だけ増加させる
				return tmp_flow;
			}
		}
	}
	return 0;
}

void reach_check(Type type,int node_id){

	can_reach[type][node_id] = true;
	int base;

	if(type == FROM_S){
		base = 1;
	}else{
		base = 0; //★逆向きに進めれば良いため★
	}

	for(int i = 0; i < G[node_id].size(); i++){
		if(G[node_id][i].capacity == base && can_reach[type][G[node_id][i].to] == false){
			reach_check(type,G[node_id][i].to);
		}
	}
}


//sourceからsinkへの最大流を求める
int max_flow(int source,int sink){ //source:始点 sink:終点
	int flow = 0,add;
	while(true){ //増加パスが存在する限り、流量を追加し続ける
		for(int i = 0; i < V; i++)used[i] = false;
		add = dfs(source,sink,BIG_NUM);
		if(add == 0)break;
		flow += add;
	}
	return flow;
}

void func(){

	for(int i = 0; i < N; i++){
		G[i].clear();
		can_reach[FROM_S][i] = false;
		can_reach[FROM_T][i] = false;
	}

	S--;
	T--;

	int from,to;
	for(int loop = 0; loop < M; loop++){
		scanf("%d %d",&from,&to);
		from--;
		to--;
		add_edge(from,to,1);
	}

	V = N;

	int FLOW = max_flow(S,T);
	//printf("FLOW:%d\n",FLOW);
	//return;
	int MAX_FLOW = FLOW;

	reach_check(FROM_S,S);
	reach_check(FROM_T,T);

	int num_edge = 0,diff;

	for(int i = 0; i < N; i++){
		for(int k = 0; k < G[i].size(); k++){
			if(G[i][k].is_rev == true || G[i][k].capacity == 0 ||
					can_reach[FROM_S][G[i][k].to] == false || can_reach[FROM_T][i] == false)continue; //逆辺または、最大流達成のために使用した辺はSKIP

			//★★経路に重なりがあるかも知れないので、仮にcan_reachが両方trueでも、流量が1増えるとは限らない★★

			//最大流達成の際に使用していない辺のみ、向きを逆転させれば、総経路が1増える可能性がある

			//辺の向きを逆転させる
			G[i][k].capacity = 0;
			G[G[i][k].to][G[i][k].rev_index].capacity = 1;

			//printf("%d-%dを逆転\n",i,G[i][k].to);
			//S→T方向に流す
			diff = max_flow(S,T);

			//printf("diff:%d\n",diff);
			//return;

			if(diff == 1){ //流量が増加した場合
				num_edge++;
				MAX_FLOW = FLOW+1;

				if(i != T){
					max_flow(T,i); //T→iに押し戻す
				}
				if(G[i][k].to != S){
					max_flow(G[i][k].to,S); //G[i][k].to→Sに押し戻す
				}
			}

			//辺の向きを元に戻す
			G[i][k].capacity = 1;
			G[G[i][k].to][G[i][k].rev_index].capacity = 0;
		}
	}

	printf("%d %d\n",MAX_FLOW,num_edge);
}


int main(){

	while(true){
		scanf("%d %d %d %d",&N,&M,&S,&T);
		if(N == 0 && M == 0 && S == 0 && T == 0)break;

		func();
	}

	return 0;
}



Measured memory_bytes: 3656