10
4 2
7 4
2 6
2 5
4 8
10 3
2 9
9 1
5 10
 10
5 10
7 8
8 3
2 6
3 2
9 7
4 5
10 1
6 4
 4
4 1
4 3
4 2
 3
3 1
1 2
 9
1 2
1 3
1 4
1 5
1 6
6 7
6 8
8 9
 5
1 5
2 3
2 4
1 2
 8
6 1
4 7
4 8
8 5
7 6
4 3
4 2
 7
5 6
5 7
5 1
7 4
6 3
3 2
 3
1 3
3 2
 2
1 2
 5
5 4
4 3
3 1
5 2
 6
1 6
3 1
6 4
5 3
2 5
 11
8 9
2 7
1 11
3 2
9 1
8 5
8 6
5 4
4 10
8 3
 11
11 9
6 7
7 1
8 11
5 6
3 5
9 3
10 8
2 4
4 10
 12
12 6
6 7
8 11
4 8
10 4
12 3
2 10
6 2
12 9
4 1
9 5

-1
 9
 1
 1
 3
 3
 -1
 -1
 1
 1
 1
 5
 1
 5
 -1

#include <bits/stdc++.h>
const int INF = 1e9;
using namespace std;
template <typename T, typename U>
ostream& operator<<(ostream& os, const pair<T, U>& p) {
  cout << '(' << p.first << ' ' << p.second << ')';
  return os;
}
template <typename T>
void dpite(T a, T b) {
  return;
}
template <typename T>
void pite(T a, T b) {
  for (T ite = a; ite != b; ite++) cout << (ite == a ? "" : " ") << *ite;
  cout << '\n';
}
template <typename T>
bool chmax(T& a, T b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}
template <typename T>
bool chmin(T& a, T b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}
void ios_init() {
  ios::sync_with_stdio(false);
  cin.tie(0);
}
class Edge {
 public:
  int to = -1, from = -1, rev = -1;
  long long cost = -1;
  Edge() {}
  Edge(int x, long long y) {
    to = x;
    cost = y;
  }
  Edge(int x, int y, long long z) {
    from = x;
    to = y;
    cost = z;
  }
  Edge(int x, int y, int r, long long z) {
    from = x;
    to = y;
    cost = z;
    rev = r;
  }
  bool operator<(const Edge& x) const {
    if (cost != x.cost) return cost < x.cost;
    return to < x.to;
  }
  bool operator>(const Edge& x) const {
    if (cost != x.cost) return cost > x.cost;
    return to > x.to;
  }
};
class Graph {
 private:
  vector<set<Edge>> v;
  int n;

 public:
  Graph(int x) {
    n = x;
    v = vector<set<Edge>>(x);
  }
  Graph() {}
  set<Edge>& operator[](int x) { return v[x]; }
  const set<Edge>& operator[](int x) const { return v[x]; }
  int size() const { return n; }
  void add_edge(int from, Edge e) { v[from].insert(e); }
  void add_edge(int from, int to, long long cost = -1, int rev = -1) {
    add_edge(from, Edge(from, to, rev, cost));
  }
  void add_uedge(int from, int to, long long cost = -1) {
    add_edge(from, to, cost);
    add_edge(to, from, cost);
  }
};
vector<long long> dijkstra(int from, const Graph& v) {
  vector<long long> dist(v.size(), INF);
  priority_queue<Edge, vector<Edge>, greater<Edge>> que;
  que.push(Edge(from, 0));
  while (!que.empty()) {
    Edge e = que.top();
    que.pop();
    if (dist[e.to] == INF) {
      dist[e.to] = e.cost;
      for (auto to : v[e.to]) {
        if (dist[to.to] == INF) que.push(Edge(to.to, e.cost + to.cost));
      }
    }
  }
  return dist;
}
vector<long long> bellmanford(int from, const Graph& g) {
  vector<long long> res(g.size(), INF);
  res[from] = 0;
  bool conf = true;
  int cnt = 0;
  while (conf) {
    conf = false;
    for (int i = 0; i < g.size(); i++) {
      if (res[i] != INF)
        for (const auto& e : g[i]) {
          if (res[e.to] > res[i] + e.cost) {
            conf = true;
            res[e.to] = res[i] + e.cost;
          }
        }
    }
    if (cnt > g.size() + 5) return vector<long long>();
    cnt++;
  }
  return res;
}
Graph prim(const Graph g) {
  using T = tuple<long long, int, int>;
  priority_queue<T, vector<T>, greater<T>> qu;
  int n = g.size();
  assert(n != 0);
  vector<bool> added(n, false);
  qu.emplace(0, 0, 0);
  Graph res(n);
  while (!qu.empty()) {
    int from, to;
    long long cost;
    tie(cost, from, to) = qu.top();
    qu.pop();
    if (!added[to]) {
      added[to] = true;
      res.add_edge(from, to, cost);
      res.add_edge(to, from, cost);
      for (const auto& e : g[to]) {
        if (!added[e.to]) {
          qu.emplace(e.cost, to, e.to);
        }
      }
    }
  }
  return res;
}
vector<int> tree_getorder(const Graph& g, int root) {
  vector<int> res;
  function<void(int p, int pre)> func = [&](int p, int pre) {
    for (auto& e : g[p]) {
      if (e.to != pre) {
        func(e.to, p);
      }
    }
    res.push_back(p);
  };
  func(root, -1);
  return res;
}
vector<int> tree_getpar(const Graph& g, int root) {
  vector<int> par(g.size(), root);
  function<void(int p, int pre)> func = [&](int p, int pre) {
    par[p] = pre;
    for (auto& e : g[p]) {
      if (e.to != pre) {
        func(e.to, p);
      }
    }
  };
  func(root, root);
  return par;
}
vector<int> toposort(const Graph& g, int start) {
  int n = g.size();
  vector<int> res;
  res.reserve(n);
  vector<bool> used(n, false);
  function<void(int)> rec = [&](int p) {
    if (used[p]) return;
    used[p] = true;
    for (auto&& e : g[p]) {
      rec(e.to);
    }
    res.push_back(p);
  };
  rec(start);
  return res;
}
tuple<long long, int, int> getTreeDiameter(const Graph& g) {
  using pair<int, int> = pair<long long, int>;
  function<pair<int, int>(int, int)> dfs = [&](int p,
                                               int par) -> pair<int, int> {
    pair<int, int> res = {0, p};
    for (auto&& e : g[p]) {
      if (e.to == par) continue;
      auto v = dfs(e.to, p);
      v.first += e.cost;
      res = max(res, v);
    }
    return res;
  };
  auto ap1 = dfs(0, -1);
  auto ap2 = dfs(ap1.second, -1);
  return make_tuple(ap2.first, ap2.second, ap1.second);
}
pair<int, int> getTreeCenter(const Graph& g) {
  long long di;
  int x, y;
  tie(di, x, y) = getTreeDiameter(g);
  pair<int, int> res(-1, -1);
  long long mi;
  function<long long(int, int)> rec = [&](int p, int par) -> long long {
    if (p == y) {
      return 0;
    }
    long long ress = -1;
    for (auto&& e : g[p])
      if (e.to != par) {
        long long v = rec(e.to, p);
        if (v != -1) {
          v += e.cost;
          ress = v;
          v = max(v, di - (v));
          if (mi > v) {
            mi = v;
            res = {p, -1};
          } else if (mi == v) {
            res.second = p;
          }
        }
      }
    return ress;
  };
  rec(x, -1);
  return res;
}
void vizGraph(const Graph& g, bool with_dir = false, bool with_cap = false) {
  ofstream ofs("./out.dot");
  if (with_dir)
    ofs << "graph graph_name {" << '\n';
  else
    ofs << "digraph graph_name {" << '\n';
  for (int i = 0; i < (int)g.size(); i++) {
    if (!g[i].size()) continue;
    for (const auto& e : g[i]) {
      if (with_dir) {
        if (e.to > i) ofs << "    \"" << i << "\" -- \"" << e.to << '"';
      } else
        ofs << "    \"" << i << "\" -> \"" << e.to << '"';
      if (with_cap) {
        ofs << " [ label = \"" << (e.cost == INF ? "inf" : to_string(e.cost))
            << "\"];";
      }
      if (!with_dir or e.to > i) ofs << '\n';
    }
  }
  ofs << "}" << '\n';
  ofs.close();
  system("dot -T png out.dot > sample.png");
}
int main() {
  ios_init();
  int n;
  while (cin >> n) {
    Graph g(n);
    for (int i = (0); i < (n - 1); ++i) {
      int a, b;
      cin >> a >> b;
      a--;
      b--;
      g.add_uedge(a, b, 1);
    }
    function<int(int, int)> dfs0 = [&](int p, int pre) -> int {
      set<int> se;
      int num = int((g[p]).size());
      vector<Edge> era;
      for (auto&& e : g[p])
        if (pre != e.to) {
          int res = dfs0(e.to, p);
          if (res == -1) continue;
          if (se.count(res)) {
            era.push_back(e);
            num--;
          } else {
            se.insert(res);
          }
        }
      for (auto&& e : era) {
        g[p].erase(e);
      }
      if (int((se).size()) == 1) {
        return *se.begin() + 1;
      } else if (int((se).size()) == 0) {
        return 1;
      } else {
        return -1;
      }
    };
    function<int(int, int, int)> check = [&](int p, int pre, int r) -> int {
      if (int((g[p]).size()) > 2) return -INF;
      int res = 1;
      for (auto&& e : g[p])
        if (e.to != pre) {
          res += check(e.to, p, r);
        }
      return res;
    };
    auto res = getTreeCenter(g);
    true;
    dfs0(res.first, -1);
    if (res.second != -1) dfs0(res.second, -1);
    auto ans = check(res.first, -1, res.first);
    if (ans < 0)
      cout << -1 << '\n';
    else
      cout << ans - 1 << '\n';
  }
  return 0;
}
