use std::io::*;
use std::str::FromStr;

fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().expect("failed to parse token")
}

// a x + b y = gcd(a, b)
fn extgcd(a: i64, b: i64, x: &mut i64, y: &mut i64) -> i64 {
    let mut g = a;
    *x = 1;
    *y = 0;
    if b != 0 {
        g = extgcd(b, a % b, y, x);
        *y -= (a / b) * *x;
    }
    g
}

fn inv_mod(a: i64, modulo: i64) -> i64 {
    let (mut x, mut y) = (0, 0);
    if extgcd(a, modulo, &mut x, &mut y) == 1 {
        return (x + modulo) % modulo;
    }
    0
}

const MOD: i64 = 1e+9 as i64 + 7;
static mut FACTORIAL: [i64; 10000] = [0; 10000];
fn fact(n: usize) -> i64 {
    unsafe { FACTORIAL[n] }
}
fn combi(n: usize, m: usize) -> i64 {
    if n < m { return 0; }
    unsafe {
        FACTORIAL[n] * inv_mod(FACTORIAL[m] * FACTORIAL[n - m] % MOD, MOD) % MOD
    }
}

fn solve(n: usize, vs: &Vec<usize>) -> i64 {
    let mut dp = vec![0; n + 1];
    dp[0] = 1;
    for m in vs {
        let mut ndp = vec![0; n + 1];
        for j in 0..m+1 {
            let cnt = combi(*m, j) * fact(*m) % MOD * inv_mod(fact(m - j), MOD) % MOD;
            for i in 0..n+1 {
                if i + j > n { break; }
                ndp[i + j] = (ndp[i + j] + cnt * dp[i]) % MOD;
            }
        }
        dp = ndp;
    }
    let mut ans = 0;
    let mut sign = 1;
    for i in 0..n {
        ans = (ans + dp[i] * fact(n - i) % MOD * sign + MOD) % MOD;
        sign *= -1;
        // println!("{}", dp[i]);
    }
    ans
}

type Weight = i32;
#[derive(Clone, Debug)]
struct Edge {
    index: usize,
    src: usize,
    dest: usize,
    weight: Weight,
}
impl Edge {
    fn new(index: usize, src: usize, dest: usize, weight: Weight) -> Edge {
        Edge {
            index: index,
            src: src,
            dest: dest,
            weight: weight,
        }
    }
}
type Edges = Vec<Edge>;
type Graph = Vec<Edges>;
fn graph_new(n: usize) -> Graph {
    vec![vec![]; n]
}
fn add_bi_edge(graph: &mut Graph, index: &mut usize, src: usize, dest: usize, weight: Weight) {
    graph[src].push(Edge::new(*index, src, dest, weight));
    graph[dest].push(Edge::new(*index, dest, src, weight));
    *index += 1;
}

fn dfs(g: &Graph, from: usize, parent: usize) -> usize {
    let mut ret = 1;
    for edge in g[from].iter() {
        if edge.dest == parent { continue; }
        ret += dfs(g, edge.dest, from);
    }
    ret
}

fn main() {
    unsafe {
        FACTORIAL[0] = 1;
        for i in 1..10000 {
            FACTORIAL[i] = (FACTORIAL[i - 1] * i as i64) % MOD;
        }
    }
    let n: usize = read();
    let mut g: Graph = graph_new(n);
    let mut e = 0;
    for _ in 0..n-1 {
        let mut a: usize = read();
        let mut b: usize = read();
        a -= 1; b -= 1;
        add_bi_edge(&mut g, &mut e, a, b, 0);
    }
    let mut max_sub_trees = vec![];
    for i in 0..n {
        let mut max_sub_tree = 0;
        for edge in g[i].iter() {
            max_sub_tree = std::cmp::max(max_sub_tree, dfs(&g, edge.dest, i));
        }
        max_sub_trees.push((max_sub_tree, i));
    }
    max_sub_trees.sort();
    if max_sub_trees[0].0 == max_sub_trees[1].0 {
        println!("{}", fact(n / 2) * fact(n / 2) % MOD);
        return;
    }
    let center = max_sub_trees[0].1;
    let mut vs = vec![];
    for edge in g[center].iter() {
        vs.push(dfs(&g, edge.dest, center));
    }
    let ans = solve(n, &vs);
    println!("{}", ans);
}

Measured memory_bytes: 4732