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

#[allow(dead_code)]
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")
}
type Weight = i64;
#[allow(dead_code)]
#[derive(Clone, Debug, Eq, PartialEq)]
struct Edge {
    index: usize,
    src: usize,
    dest: usize,
    weight: Weight,
}
#[allow(dead_code)]
impl Edge {
    fn new(index: usize, src: usize, dest: usize, weight: Weight) -> Edge {
        Edge {
            index: index,
            src: src,
            dest: dest,
            weight: weight,
        }
    }
}
impl std::cmp::Ord for Edge {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        (self.weight, self.src, self.dest).cmp(&(other.weight, other.src, other.dest))
    }
}
impl std::cmp::PartialOrd for Edge {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}
type Edges = Vec<Edge>;
type Graph = Vec<Edges>;
#[allow(dead_code)]
fn graph_new(n: usize) -> Graph {
    vec![vec![]; n]
}
#[allow(dead_code)]
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;
}
#[allow(dead_code)]
fn add_uni_edge(graph: &mut Graph, index: &mut usize, src: usize, dest: usize, weight: Weight) {
    graph[src].push(Edge::new(*index, src, dest, weight));
    *index += 1;
}

const MOD: i64 = 1e+9 as i64 + 7;
const FACT_MAX: usize = 10000;
static mut FACTORIAL2: [i64; FACT_MAX + 1] = [0; FACT_MAX + 1];
fn init_fact2() {
    unsafe {
        if FACTORIAL2[0] == 0 {
            FACTORIAL2[0] = 1;
            FACTORIAL2[1] = 0;
            for i in 2..FACT_MAX + 1 {
                FACTORIAL2[i] = (FACTORIAL2[i - 2] * (i - 1) as i64) % MOD;
            }
        }
    }
}

#[allow(dead_code)]
fn fact2(n: usize) -> i64 {
    init_fact2();
    unsafe { FACTORIAL2[n] }
}

fn calc(g: &Graph, from: usize, parent: usize) -> Vec<Vec<i64>> {
    let mut ret = vec![vec![0; 2]; 2];
    ret[0][1] = 1;
    for e in g[from].iter() {
        if e.dest == parent {
            continue;
        }
        let nret = calc(g, e.dest, from);
        let m = ret[0].len() + nret[0].len() - 1;
        let mut temp = vec![vec![0; m]; 2];
        for f in 0..2 {
            for t in 0..2 {
                for i in 0..ret[0].len() {
                    for j in 0..nret[0].len() {
                        // connect
                        let d = (f + t) % 2;
                        temp[d][i + j] = (temp[d][i + j] + ret[f][i] * nret[t][j]) % MOD;
                        // divide
                        let d = (f + t + 1) % 2;
                        temp[d][i] = (temp[d][i] + ret[f][i] * nret[t][j] % MOD * fact2(j)) % MOD;
                    }
                }
            }
        }
        ret = temp;
    }
    return ret;
}

fn main() {
    let n = read::<usize>();
    let mut g = graph_new(n);
    let mut index = 0;
    for _i in 0..n - 1 {
        let f = read::<usize>() - 1;
        let t = read::<usize>() - 1;
        add_bi_edge(&mut g, &mut index, f, t, 1);
    }
    let root_dp = calc(&g, 0, 0);
    let mut ans = 0;
    for i in 0..(n + 1) {
        ans = (ans + root_dp[0][i] * fact2(i)) % MOD;
        ans = (ans - root_dp[1][i] * fact2(i) + MOD * MOD) % MOD;
    }
    println!("{}", ans);
}


Measured memory_bytes: 8060