#include <bits/stdc++.h>
#define GET_MACRO(_1,_2,_3,_4,_5,_6,_7,_8,NAME,...) NAME
#define pr(...) cerr<< GET_MACRO(__VA_ARGS__,pr8,pr7,pr6,pr5,pr4,pr3,pr2,pr1)(__VA_ARGS__) <<endl
#define pr1(a) (#a)<<"="<<(a)<<" "
#define pr2(a,b) pr1(a)<<pr1(b)
#define pr3(a,b,c) pr1(a)<<pr2(b,c)
#define pr4(a,b,c,d) pr1(a)<<pr3(b,c,d)
#define pr5(a,b,c,d,e) pr1(a)<<pr4(b,c,d,e)
#define pr6(a,b,c,d,e,f) pr1(a)<<pr5(b,c,d,e,f)
#define pr7(a,b,c,d,e,f,g) pr1(a)<<pr6(b,c,d,e,f,g)
#define pr8(a,b,c,d,e,f,g,h) pr1(a)<<pr7(b,c,d,e,f,g,h)
using namespace std;
using Int = long long;
using _int = int;
using ll = long long;
using Double = long double;
const Int INF = (1LL<<55)+1e9; // ~ 3.6 * 1e16
const Int mod = (1e9)+7;
const Double EPS = 1e-8;
const Double PI = 6.0 * asin((Double)0.5);
using P = pair<Int,Int>;
using T = tuple<Int,Int,Int>;
template<class T> T Max(T &a,T b){return a=max(a,b);}
template<class T> T Min(T &a,T b){return a=min(a,b);}
template<class T1, class T2> ostream& operator<<(ostream& o,pair<T1,T2> p){return o<<"("<<p.first<<","<<p.second<<")";}
template<class T1, class T2, class T3> ostream& operator<<(ostream& o,tuple<T1,T2,T3> t){
  return o<<"("<<get<0>(t)<<","<<get<1>(t)<<","<<get<2>(t)<<")";}
template<class T1, class T2> istream& operator>>(istream& i,pair<T1,T2> &p){return i>>p.first>>p.second;}
template<class T> ostream& operator<<(ostream& o,vector<T> &a){Int i=0;for(T t:a)o<<(i++?" ":"")<<t;return o;}
template<class T> istream& operator>>(istream& i,vector<T> &a){for(T &t:a)i>>t;return i;}
template<class T>void prArr(T a,string s=" "){Int i=0;for(T t:a)cout<<(i++?s:"")<<t;cout<<endl;}

class TreeSize{
public:
  Int V;                        //ノード数
  Int root;                     //根
  vector<vector<Int> > G;       //Graph
  vector<Int> w;                //ノードのに重みが有る場合デフォルトでは1
  vector<Int> sz;               //部分木のサイズ
  Int ok;
  TreeSize():V(-1){};
  TreeSize(Int V,Int root = 0):V(V),root(root),G(V),w(V,1),sz(V,0),ok(0){}
  TreeSize(vector<vector<Int> > G,Int root = 0):V(G.size()),root(root),G(G),w(V,1),sz(V,0),ok(0){}
  void resize(Int n){*this = TreeSize(n);}
  Int& operator [](Int i){return w[i];}
  
  void add_edge(Int a,Int b){
    ok = false;
    assert(a < V && b < V);
    assert(a >= 0 && b >= 0);
    G[a].push_back(b);
    G[b].push_back(a);
  }
  
  void build(Int root=-1){
    ok = 1;
    if(root != -1) this->root = root;
    dfs(this->root,-1);
  }
  
  Int dfs(Int pos,Int pre = -1){
    sz[pos] = w[pos];
    for(Int to:G[pos]) if(to != pre) sz[pos] += dfs(to, pos);
    return sz[pos];
  }
  Int size(Int i){assert(ok);return sz[i];}
};

class TreeParent{
public:
  Int V;                        //ノード数
  Int root;                     //根
  vector<vector<Int> > G;       //Graph
  vector<Int> parent;           //親
  Int ok;
  TreeParent():V(-1){};
  TreeParent(Int V,Int root = 0):V(V),root(root),G(V),parent(V),ok(0){}
  TreeParent(vector<vector<Int> > G,Int root = 0):V(G.size()),root(root),G(G),parent(V),ok(0){}
  void resize(Int n){*this = TreeParent(n);}
  void add_edge(Int a,Int b){
    ok = false;
    assert(a < V && b < V);
    assert(a >= 0 && b >= 0);
    G[a].push_back(b);
    G[b].push_back(a);
  }
  void build(Int root = -1){
    ok = 1;
    if(root != -1) this->root = root;
    function<void(Int,Int)> dfs = [&](Int pos,Int pre){
      parent[pos] = pre;
      for(Int to:G[pos]) if(to != pre) dfs(to, pos);
    };
    dfs(this->root, -1);
  }
  Int get(Int u){assert(ok); assert(0 <= u && u < V); return parent[u];}
  
};

Int f(Int n){
  static Int used[10000] = {}, mem[10000];
  if(n % 2 == 0 || n < 0) return 0;
  if(n <= 2) return n;
  if(used[n]++) return mem[n];
  return mem[n] = n * f(n-2) % mod;
}


Int dp[5010][5010][2];
signed main(){
  srand((unsigned)time(NULL));
  cin.tie(0);
  ios_base::sync_with_stdio(0);
  cout << fixed << setprecision(12);
  Int N;
  cin>>N;

  vector<vector<Int> > G(N);
  for(Int i=0;i<N-1;i++){
    Int x, y;
    cin>>x>>y; x--, y--;
    G[x].push_back(y);
    G[y].push_back(x);

  }
  TreeSize TS(G);TS.build();
  TreeParent TP(G);TP.build();
  
  vector<Int> A(N); iota(A.begin(), A.end(), 0);
  sort(A.begin(), A.end(), [&](Int a,Int b){return TS.size(a) < TS.size(b);});


  for(Int i=0;i<N;i++) dp[i][0][0] = 1;
  
  //今の頂点、　部分木の連結成分の個数, 白いエッジの偶奇。
  vector<Int> sum(N);
  for(Int u:A){
    if(u == 0) break;
    Int p = TP.get(u);
    sum[p] += TS.size(u);
    for(Int psz = sum[p] - 1; psz >= 0; psz--){
      Int a[2] = {dp[p][psz][0], dp[p][psz][1]};
      dp[p][psz][0] =  dp[p][psz][1] = 0;
      for(Int pp = 0; pp < 2; pp++){
	if(a[pp] == 0) continue;
	for(Int usz = 0; usz < TS.size(u) && usz + psz < sum[p]; usz++)
	  for(Int up = 0; up < 2; up++){
	    
	    { //親とつなげない。
	      Int np = pp ^ up ^ 1;
	      Int nsz = psz;
	      dp[p][nsz][np] += (a[pp] * dp[u][usz][up] % mod) * f(usz);
	      dp[p][nsz][np] %= mod;
	    }

	    
	    { //親とつなげる。
	      Int np = pp ^ up;
	      Int nsz = psz + usz + 1;
	      dp[p][nsz][np] += a[pp] * dp[u][usz][up] % mod;
	      dp[p][nsz][np] %= mod;
	    }
	  }
      }
    }
  }
  
  Int ans = 0;
  for(Int p = 0; p < 2; p++)
    for(Int sz = 0; sz < N; sz++){
      ans = ans + dp[0][sz][p] * (p == 0? 1:-1) * f(sz);
      ans = (ans + mod)%mod;
    }
  cout<<ans<<endl;
  return 0;
}


Measured memory_bytes: 391936