#include <bits/stdc++.h>   using namespace std;   using ll = long long;   using pl = pair<ll, ll>;   using vll = vector<ll>;   using vpl = vector<pl>;   using mat = vector<vll>;   const ll MAX = 1e5;   const ll mod = 1e9 + 7;   template <typename T>   ostream &operator<<(ostream &os, const vector<T> &v) {     for (auto &ele : v) {       cout << ele <<    ;     }     return os;   }   template <typename T, typename U>   ostream &operator<<(ostream &os, const pair<T, U> &p) {     return os <<  (  << p.first <<  ,  << p.second <<  ) ;   }   template <typename T>   istream &operator>>(istream &in, vector<T> &v) {     for (auto &ele : v) {       cin >> ele;     }     return in;   }   template <typename A, typename B>   string to_string(pair<A, B> p);   template <typename A, typename B, typename C>   string to_string(tuple<A, B, C> p);   template <typename A, typename B, typename C, typename D>   string to_string(tuple<A, B, C, D> p);   string to_string(const string &s) { return     + s +    ; }   string to_string(const char *s) { return to_string((string)s); }   string to_string(bool b) { return (b ?  true  :  false ); }   string to_string(vector<bool> v) {     bool first = true;     string res =  { ;     for (int i = 0; i < static_cast<int>(v.size()); i++) {       if (!first) {         res +=  ,  ;       }       first = false;       res += to_string(v[i]);     }     res +=  } ;     return res;   }   template <size_t N>   string to_string(bitset<N> v) {     string res =   ;     for (size_t i = 0; i < N; i++) {       res += static_cast<char>( 0  + v[i]);     }     return res;   }   template <typename A>   string to_string(A v) {     bool first = true;     string res =  { ;     for (const auto &x : v) {       if (!first) {         res +=  ,  ;       }       first = false;       res += to_string(x);     }     res +=  } ;     return res;   }   template <typename A, typename B>   string to_string(pair<A, B> p) {     return  (  + to_string(p.first) +  ,   + to_string(p.second) +  ) ;   }   template <typename A, typename B, typename C>   string to_string(tuple<A, B, C> p) {     return  (  + to_string(get<0>(p)) +  ,   + to_string(get<1>(p)) +  ,   +            to_string(get<2>(p)) +  ) ;   }   template <typename A, typename B, typename C, typename D>   string to_string(tuple<A, B, C, D> p) {     return  (  + to_string(get<0>(p)) +  ,   + to_string(get<1>(p)) +  ,   +            to_string(get<2>(p)) +  ,   + to_string(get<3>(p)) +  ) ;   }   void debug_out() { cerr << endl; }   template <typename Head, typename... Tail>   void debug_out(Head H, Tail... T) {     cerr <<     << to_string(H);     debug_out(T...);   }   template <typename T>   class graph {    public:     struct edge {       int from;       int to;       T cost;     };     vector<edge> edges;     vector<vector<int>> g;     int n;     graph(int _n) : n(_n) { g.resize(n); }     virtual int add(int from, int to, T cost) = 0;   };   template <typename T>   class forest : public graph<T> {    public:     using graph<T>::edges;     using graph<T>::g;     using graph<T>::n;     forest(int _n) : graph<T>(_n) {}     int add(int from, int to, T cost = 1) {       assert(0 <= from && from < n && 0 <= to && to < n);       int id = (int)edges.size();       assert(id < n - 1);       g[from].push_back(id);       g[to].push_back(id);       edges.push_back({from, to, cost});       return id;     }   };   template <typename T>   class dfs_forest : public forest<T> {    public:     using forest<T>::edges;     using forest<T>::g;     using forest<T>::n;     vector<int> pv;     vector<int> pe;     vector<int> order;     vector<int> pos;     vector<int> end;     vector<int> sz;     vector<int> root;     vector<int> depth;     vector<T> dist;     dfs_forest(int _n) : forest<T>(_n) {}     void init() {       pv = vector<int>(n, -1);       pe = vector<int>(n, -1);       order.clear();       pos = vector<int>(n, -1);       end = vector<int>(n, -1);       sz = vector<int>(n, 0);       root = vector<int>(n, -1);       depth = vector<int>(n, -1);       dist = vector<T>(n);     }     void clear() {       pv.clear();       pe.clear();       order.clear();       pos.clear();       end.clear();       sz.clear();       root.clear();       depth.clear();       dist.clear();     }       private:     void do_dfs(int v) {       pos[v] = (int)order.size();       order.push_back(v);       sz[v] = 1;       for (int id : g[v]) {         if (id == pe[v]) {           continue;         }         auto &e = edges[id];         int to = e.from ^ e.to ^ v;         depth[to] = depth[v] + 1;         dist[to] = dist[v] + e.cost;         pv[to] = v;         pe[to] = id;         root[to] = (root[v] != -1 ? root[v] : to);         do_dfs(to);         sz[v] += sz[to];       }       end[v] = (int)order.size() - 1;     }     void do_dfs_from(int v) {       depth[v] = 0;       dist[v] = T{};       root[v] = v;       pv[v] = pe[v] = -1;       do_dfs(v);     }       public:     void dfs(int v, bool clear_order = true) {       if (pv.empty()) {         init();       } else {         if (clear_order) {           order.clear();         }       }       do_dfs_from(v);     }     void dfs_all() {       init();       for (int v = 0; v < n; v++) {         if (depth[v] == -1) {           do_dfs_from(v);         }       }       assert((int)order.size() == n);     }   };   void solve() {     ll N;     cin >> N;     dfs_forest<ll> g(N);     for (ll i = (0); (1) > 0 ? i < (N - 1) : i >= (N - 1); i += (1)) {       ll x, y;       cin >> x >> y;       x -= 1, y -= 1;       g.add(x, y);     }     g.dfs(0);     vll cnt(2, 0);     cerr <<  [           <<  g.depth           <<  ]: ,         debug_out(g.depth);     for (ll i = (0); (1) > 0 ? i < (N) : i >= (N); i += (1)) {       cnt[g.depth[i] % 2] += 1;     }     cout << min(cnt[0], cnt[1]) - 1 << endl;   }   int32_t main() {     ios_base::sync_with_stdio(false);     cin.tie(NULL);     cout.tie(NULL);     ll tc = 1;     while (tc--) {       solve();     }     return 0;   }