#include <bits/stdc++.h>

#ifdef DEBUG
#include <Mylib/Debug/debug.cpp>
#else
#define dump(...) ((void)0)
#endif

template <typename T, typename U>
bool chmin(T &a, const U &b){
  return (a > b ? a = b, true : false);
}

template <typename T, typename U>
bool chmax(T &a, const U &b){
  return (a < b ? a = b, true : false);
}

template <typename T, size_t N, typename U>
void fill_array(T (&a)[N], const U &v){
  std::fill((U*)a, (U*)(a + N), v);
}

template <typename T, size_t N, size_t I = N>
auto make_vector(const std::array<int, N> &a, T value = T()){
  static_assert(I >= 1);
  static_assert(N >= 1);
  if constexpr (I == 1){
    return std::vector<T>(a[N - I], value);
  }else{
    return std::vector(a[N - I], make_vector<T, N, I - 1>(a, value));
  }
}

template <typename T>
std::ostream& operator<<(std::ostream &s, const std::vector<T> &a){
  for(auto it = a.begin(); it != a.end(); ++it){
    if(it != a.begin()) s << " ";
    s << *it;
  }
  return s;
}

template <typename T>
std::istream& operator>>(std::istream &s, std::vector<T> &a){
  for(auto &x : a) s >> x;
  return s;
}

/**
 * @title Basic graph
 * @docs graph.md
 */
template <typename T>
struct Edge {
  int from, to;
  T cost;
  int index = -1;
  Edge(){}
  Edge(int from, int to, T cost): from(from), to(to), cost(cost){}
  Edge(int from, int to, T cost, int index): from(from), to(to), cost(cost), index(index){}
};

template <typename T>
struct Graph {
  using weight_type = T;
  using edge_type = Edge<T>;

  std::vector<std::vector<Edge<T>>> data;

  auto& operator[](size_t i){return data[i];}
  const auto& operator[](size_t i) const {return data[i];}

  auto begin() const {return data.begin();}
  auto end() const {return data.end();}

  Graph(){}
  Graph(int N): data(N){}

  bool empty() const {return data.empty();}
  int size() const {return data.size();}

  void add_edge(int i, int j, T w, int index = -1){
    data[i].emplace_back(i, j, w, index);
  }

  void add_undirected(int i, int j, T w, int index = -1){
    add_edge(i, j, w, index);
    add_edge(j, i, w, index);
  }

  template <size_t I, bool DIRECTED = true, bool WEIGHTED = true>
  void read(int M){
    for(int i = 0; i < M; ++i){
      int u, v; std::cin >> u >> v;
      u -= I;
      v -= I;
      T w = 1;
      if(WEIGHTED) std::cin >> w;
      if(DIRECTED) add_edge(u, v, w, i);
      else add_undirected(u, v, w, i);
    }
  }
};

template <typename T>
using Tree = Graph<T>;

/**
 * @title Modint
 * @docs mint.md
 */
template <int32_t M>
class ModInt {
public:
  constexpr static int32_t MOD = M;
  uint32_t val;

  constexpr ModInt(): val(0){}
  constexpr ModInt(int64_t n){
    if(n >= M) val = n % M;
    else if(n < 0) val = n % M + M;
    else val = n;
  }

  constexpr auto& operator=(const ModInt &a){val = a.val; return *this;}
  constexpr auto& operator+=(const ModInt &a){
    if(val + a.val >= M) val = (uint64_t)val + a.val - M;
    else val += a.val;
    return *this;
  }
  constexpr auto& operator-=(const ModInt &a){
    if(val < a.val) val += M;
    val -= a.val;
    return *this;
  }
  constexpr auto& operator*=(const ModInt &a){
    val = (uint64_t)val * a.val % M;
    return *this;
  }
  constexpr auto& operator/=(const ModInt &a){
    val = (uint64_t)val * a.inv().val % M;
    return *this;
  }

  constexpr auto operator+(const ModInt &a) const {return ModInt(*this) += a;}
  constexpr auto operator-(const ModInt &a) const {return ModInt(*this) -= a;}
  constexpr auto operator*(const ModInt &a) const {return ModInt(*this) *= a;}
  constexpr auto operator/(const ModInt &a) const {return ModInt(*this) /= a;}

  constexpr bool operator==(const ModInt &a) const {return val == a.val;}
  constexpr bool operator!=(const ModInt &a) const {return val != a.val;}

  constexpr auto& operator++(){*this += 1; return *this;}
  constexpr auto& operator--(){*this -= 1; return *this;}

  constexpr auto operator++(int){auto t = *this; *this += 1; return t;}
  constexpr auto operator--(int){auto t = *this; *this -= 1; return t;}

  constexpr static ModInt power(int64_t n, int64_t p){
    if(p < 0) return power(n, -p).inv();

    int64_t ret = 1, e = n % M;
    for(; p; (e *= e) %= M, p >>= 1) if(p & 1) (ret *= e) %= M;
    return ret;
  }

  constexpr static ModInt inv(int64_t a){
    int64_t b = M, u = 1, v = 0;

    while(b){
      int64_t t = a / b;
      a -= t * b; std::swap(a, b);
      u -= t * v; std::swap(u, v);
    }

    u %= M;
    if(u < 0) u += M;

    return u;
  }

  constexpr static auto frac(int64_t a, int64_t b){return ModInt(a) / ModInt(b);}

  constexpr auto power(int64_t p) const {return power(val, p);}
  constexpr auto inv() const {return inv(val);}

  friend constexpr auto operator-(const ModInt &a){return ModInt(M-a.val);}

  friend constexpr auto operator+(int64_t a, const ModInt &b){return ModInt(a) + b;}
  friend constexpr auto operator-(int64_t a, const ModInt &b){return ModInt(a) - b;}
  friend constexpr auto operator*(int64_t a, const ModInt &b){return ModInt(a) * b;}
  friend constexpr auto operator/(int64_t a, const ModInt &b){return ModInt(a) / b;}

  friend std::istream& operator>>(std::istream &s, ModInt<M> &a){s >> a.val; return s;}
  friend std::ostream& operator<<(std::ostream &s, const ModInt<M> &a){s << a.val; return s;}

  template <int N>
  static auto div(){
    static auto value = inv(N);
    return value;
  }

  explicit operator int32_t() const noexcept {return val;}
  explicit operator int64_t() const noexcept {return val;}
};

/**
 * @title Factorial table
 * @docs factorial_table.md
 */
template <typename T>
class FactorialTable {
public:
  using value_type = T;

private:
  std::vector<T> f_table;
  std::vector<T> if_table;

public:
  FactorialTable(int N){
    f_table.assign(N + 1, 1);
    if_table.assign(N + 1, 1);

    for(int i = 1; i <= N; ++i){
      f_table[i] = f_table[i - 1] * i;
    }

    if_table[N] = f_table[N].inv();

    for(int i = N-1; i >= 0; --i){
      if_table[i] = if_table[i + 1] * (i + 1);
    }
  }

  T factorial(int64_t i) const {
    assert(i < (int)f_table.size());
    return f_table[i];
  }

  T inv_factorial(int64_t i) const {
    assert(i < (int)if_table.size());
    return if_table[i];
  }

  T P(int64_t n, int64_t k) const {
    if(n < k or n < 0 or k < 0) return 0;
    return factorial(n) * inv_factorial(n - k);
  }

  T C(int64_t n, int64_t k) const {
    if(n < k or n < 0 or k < 0) return 0;
    return P(n, k) * inv_factorial(k);
  }

  T H(int64_t n, int64_t k) const {
    if(n == 0 and k == 0) return 1;
    return C(n + k - 1, k);
  }
};


/**
 * @title Enumerate centroids
 * @docs centroid.md
 */
namespace enumerate_centroids_impl {
  template <typename T>
  void dfs(const Tree<T> &tree, std::vector<int> &subtree, std::vector<int> &ret, int N, int cur, int par){
    subtree[cur] = 1;
    bool check = true;

    for(auto &e : tree[cur]){
      if(e.to == par) continue;
      dfs(tree, subtree, ret, N, e.to, cur);

      if(subtree[e.to] > N / 2) check = false;
      subtree[cur] += subtree[e.to];
    }

    if(N - subtree[cur] > N / 2) check = false;

    if(check) ret.push_back(cur);
  }
}

template <typename T>
auto enumerate_centroids(const Tree<T> &tree){
  const int N = tree.size();
  std::vector<int> subtree(N), ret;
  enumerate_centroids_impl::dfs(tree, subtree, ret, N, 0, -1);
  return ret;
}





namespace solver{
  void init(){
    std::cin.tie(0);
    std::ios::sync_with_stdio(false);
    std::cout << std::fixed << std::setprecision(12);
    std::cerr << std::fixed << std::setprecision(12);
    std::cin.exceptions(std::ios_base::failbit);
  }

  using mint = ModInt<1000000007>;
  const auto ft = FactorialTable<mint>(20000);

  template <typename T>
  int subtree_size(const Tree<T> &tree, int cur, int par = -1){
    int ret = 1;

    for(auto &e : tree[cur]){
      if(e.to == par) continue;
      ret += subtree_size(tree, e.to, cur);
    }

    return ret;
  }

  mint sub(const std::vector<int> &a){
    const int N = a.size();
    const int M = std::accumulate(a.begin(), a.end(), 0);

    auto dp = make_vector<mint, 2>({N + 1, 2 * M});

    dp[0][0] = 1;

    for(int i = 0; i < N; ++i){
      for(int j = 0; j < M; ++j){
        for(int k = 0; k <= a[i]; ++k){
          mint t = ft.C(a[i], k) * ft.P(a[i], k);
          dp[i + 1][j + k] += dp[i][j] * t;
        }
      }
    }

    mint t = 0;
    for(int i = 1; i <= M; ++i){
      mint s = dp[N][i] * ft.factorial(M - i);
      t += s * (i % 2 ? 1 : -1);
    }

    mint ret = 1;

    int k = M;
    for(int i = 0; i < N; ++i){
      ret *= ft.P(k, a[i]);
      k -= a[i];
    }

    ret -= t;

    return ret;
  }

  void solve(){
    int N; std::cin >> N;
    Tree<int> tree(N);
    tree.read<1, false, false>(N - 1);

    const auto c = enumerate_centroids(tree);

    mint ans = 0;

    if(c.size() == 1){
      std::vector<int> a;
      for(auto &e : tree[c[0]]){
        a.push_back(subtree_size(tree, e.to, e.from));
      }

      ans += sub(a);
      a.push_back(1);
      ans += sub(a);
    }else{
      mint t = ft.factorial(N/2);
      ans = t * t;
    }

    std::cout << ans << "\n";
  }
}

int main(){
  solver::init();
  while(true){
    try{
      solver::solve();
    }catch(const std::istream::failure &e){
      break;
    }
  }
  return 0;
}


Measured memory_bytes: 199200