fn dfs(
    u: usize,
    p: usize,
    dpt: usize,
    memo: &mut HashMap<(usize, usize, usize), (usize, HashMap<usize, usize>)>,
    next: &Vec<Vec<usize>>,
) -> (usize, HashMap<usize, usize>) {
    let key = (u, p, dpt);
    if memo.contains_key(&key) {
        return memo[&key].clone();
    }
    let mut res = Vec::new();
    for &v in &next[u] {
        if v != p {
            let (d, l) = dfs(v, u, dpt + 1, memo, next);
            res.push((d, l));
        }
    }
    let ans = if res.len() == 0 {
        (1, HashMap::new())
    } else {
        let max_d = res.iter().map(|&(d, _)| d).max().unwrap();
        let mut new_l = HashMap::new();
        for &(_, ref l) in &res {
            merge_l(&mut new_l, &l);
        }
        if res.len() > 1 {
            new_l.insert(dpt, res.len());
        }
        (max_d + 1, new_l)
    };
    memo.insert(key, ans.clone());
    ans
}

fn merge_l(l: &mut HashMap<usize, usize>, m: &HashMap<usize, usize>) {
    for (k, v) in m.iter() {
        if !l.contains_key(k) || l[k] < *v {
            l.insert(*k, *v);
        }
    }
}

fn mul_l(l: &HashMap<usize, usize>) -> usize {
    let mut res = 1;
    for &x in l.iter().map(|(_, x)| x) {
        res *= x;
    }
    res
}

fn main() {
    let n = readln();
    let mut next: Vec<Vec<usize>> = vec![vec![]; n];
    let mut edges = Vec::new();
    for _ in 0..n - 1 {
        let (a, b): (usize, usize) = readln();
        next[a - 1].push(b - 1);
        next[b - 1].push(a - 1);
        edges.push((a - 1, b - 1));
    }

    let mut memo = HashMap::new();
    let mut answer = (usize::max_value(), usize::max_value());
    for r in 0..n {
        let (d, l) = dfs(r, usize::max_value(), 0, &mut memo, &next);
        answer = min(answer, (d, mul_l(&l)));
    }
    for (a, b) in edges {
        let (d1, l1) = dfs(a, b, 0, &mut memo, &next);
        let (d2, l2) = dfs(b, a, 0, &mut memo, &next);
        let mut new_l = HashMap::new();
        merge_l(&mut new_l, &l1);
        merge_l(&mut new_l, &l2);
        let d = max(d1, d2);
        new_l.insert(d + 1, 2);
        let ans = (d, mul_l(&new_l));
        answer = min(answer, ans);
    }
    println!("{} {}", answer.0, answer.1);
}

#[allow(unused_imports)]
use std::cmp::{max, min};
#[allow(unused_imports)]
use std::collections::{HashMap, HashSet, VecDeque};

pub trait FromLn {
    fn fromln(s: &str) -> Self;
}
pub fn readln<T: FromLn>() -> T {
    let mut buf = String::new();
    let _ = ::std::io::stdin().read_line(&mut buf).unwrap();
    T::fromln(buf.trim())
}
pub fn readlns<T: FromLn>(n: usize) -> Vec<T> {
    let mut vs = vec![];
    for _ in 0..n {
        vs.push(readln());
    }
    vs
}
macro_rules! fromln_primitives {
    ($($t:ty),*) => { $(
        impl FromLn for $t {
            fn fromln(s: &str) -> $t {
                s.parse().unwrap()
            }
        }
    )* }
}
fromln_primitives!(String, bool, f32, f64, isize, i8, i16, i32, i64, usize, u8, u16, u32, u64);
impl<T> FromLn for Vec<T>
where
    T: FromLn,
{
    fn fromln(s: &str) -> Vec<T> {
        s.split_whitespace().map(T::fromln).collect()
    }
}
impl FromLn for Vec<char> {
    fn fromln(s: &str) -> Vec<char> {
        s.chars().collect()
    }
}
macro_rules! fromln_tuple {
    ($($t:ident),*) => {
        impl<$($t),*> FromLn for ($($t),*) where $($t: FromLn),* {
            fn fromln(s: &str) -> ($($t),*) {
                let mut it = s.split_whitespace();
                let t = ($($t::fromln(it.next().unwrap())),*);
                assert_eq!(it.next(), None);
                t
            }
        }
    }
}
fromln_tuple!(A, B);
fromln_tuple!(A, B, C);
fromln_tuple!(A, B, C, D);
fromln_tuple!(A, B, C, D, E);
fromln_tuple!(A, B, C, D, E, F);


Measured memory_bytes: 10492