#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>
#include <climits>
#include <cstring>

#define rep(i, m, n) for(int i=int(m);i<int(n);i++)
#define all(c) begin(c),end(c)

template<typename T1, typename T2>
inline void chmin(T1 &a, T2 b) { if (a > b) a = b; }

template<typename T1, typename T2>
inline void chmax(T1 &a, T2 b) { if (a < b) a = b; }

typedef long long int ll;
using ll = long long int;
using ull = long long unsigned int;
using Int = long long int;
using namespace std;
#define INF (1 << 30) - 1
#define INFl (ll)5e15
#define DEBUG 0
#define dump(x)  cerr << #x << " = " << (x) << endl
#define MOD 1000000007


//edit
class UnionFind {
    vector<int> p;//p[i]はiの属する組織
public:
    UnionFind(int n) {
        p = vector<int>(n);
        for (int i = 0; i < n; i++) {
            p[i] = i;
        }
        return;
    }

/* xの属する集合を返す */
    int find(int x) {
        if (p[x] == x) return x;
        return p[x] = find(p[x]);
    }

/* yにxを統合する */
    void unite(int x, int y) {
        p[find(x)] = p[find(y)];
    }

/* xとyが属する集合が同じかを判定する */
    bool same(int x, int y) {
        return find(x) == find(y);
    }

};

class Solve {
public:
    Int N;
    vector<vector<Int>> tree;

    int dfs(int v, int p = -1) {
        int ret = 0;
        if (tree[v].size() <= 1) return -1;

        int cnt1 = 0;
        for (auto e : tree[v]) {
            if (e != p) {
                int tmp = dfs(e, v);
                if (tmp == -1) cnt1++;
                else ret += tmp;
            }
        }
        if (tree[v].size() == 2 && cnt1 == 1) {
            return -1;
        }

        ret += max(cnt1 - 1, 0);
        return ret;
    }

    void input(Int &N_, vector<vector<Int>> &tree_) {
        N = N_;
        tree = tree_;
    }


    void input() {
        cin >> N;
        tree.resize(N);
        for (int i = 0; i + 1 < N; ++i) {
            int a, b;
            cin >> a >> b;
            tree[a].push_back(b);
            tree[b].push_back(a);
        }
    }

    int solve() {

        int s = -1;
        for (int i = 0; i < N; ++i) {
            if (tree[i].size() > 2) {
                s = i;
                break;
            }
        }
        if (s == -1) {
            cout << 1 << endl;
            return 1;
        }

        int ans = dfs(s);

        cout << ans << endl;

        return ans;
    }
};

struct Fool {
    Int N;
    vector<vector<Int>> tree;

//    int dfs(int v, int p = -1) {
//        int ret = 0;
//        if (tree[v].size() <= 2) return 1;
//
//        int cnt1 = 0;
//        for (auto e : tree[v]) {
//            if (e != p) {
//                int tmp = dfs(e, v);
//                if (tmp == 1) cnt1++;
//                else ret += tmp;
//            }
//        }
//        ret += max(cnt1 - 1, 0);
//        return ret;
//    }

    void input(Int &N_, vector<vector<Int>> &tree_) {
        N = N_;
        tree = tree_;
    }


    void input() {
        cin >> N;
        tree.resize(N);
        for (int i = 0; i + 1 < N; ++i) {
            int a, b;
            cin >> a >> b;
            tree[a].push_back(b);
            tree[b].push_back(a);
        }
    }

    vector<vector<int>> dist;

    void dfs(int v, int d = 0, int p = -1) {
        dist.back()[v] = d;
        for (auto e : tree[v]) {
            if (e != p)
                dfs(e, d + 1, v);
        }
    }

    bool check(int bit) {
        dist.erase(dist.begin(), dist.end());
        for (int i = 0; i < N; ++i) {
            if (bit >> i & 1) {
                dist.push_back(vector<int>(N, -1));
                dfs(i);
            }
        }

        vector<vector<int>> idist(N, vector<int>(dist.size()));
        for (int i = 0; i < N; ++i) {
            for (int j = 0; j < dist.size(); ++j) {
                idist[i][j] = dist[j][i];
            }
        }

        set<vector<int>> st;
        for (auto e : idist) {
            st.insert(e);
        }

        return st.size() == idist.size();

    }

    int solve() {
        int ans = N;
        for (int bit = 1; bit < 1 << N; ++bit) {
            if (check(bit)) {
                int tmp = __pop_count((unsigned) bit);
                chmin(ans, tmp);
            }
        }
        cout << ans << endl;
        return ans;
    }


};

vector<vector<Int>> make_tree(Int N) {
    UnionFind uf(N);
    vector<pair<int, int>> edge;
    for (int i = 0; i + 1 < N; ++i) {
        int x = 0, y = 0;
        while (uf.same(x, y)) {
            x = rand() % N;
            y = rand() % N;
        }
        uf.unite(x, y);
        edge.emplace_back(x, y);

    }

    vector<vector<Int>> tree(N);
    for (auto e : edge) {
        tree[e.first].push_back(e.second);
        tree[e.second].push_back(e.first);
    }

    return tree;
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(10);

    bool debug = false;
//    debug = true;


    if (debug) {
        int max_n = 15;
        int min_n = 2;
        while (true) {
            Int N = rand() % (max_n - min_n + 1) + min_n;
            vector<vector<Int>> tree = make_tree(N);
            cout << "---input---" << endl;
//            cout << "N = " << N << endl;
            cout << N << endl;
//            cout << "edges " << endl;
            for (int i = 0; i < N; ++i) {
                for (auto e : tree[i]) {
                    if (i < e) {
//                        cout << "(" << i << ", " << e << ")" << endl;
                        cout << i << " " << e << endl;
                    }
                }
            }
            cout << "---result---" << endl;


            Solve solve;
            solve.input(N, tree);
            int ans1 = solve.solve();

            Fool fool;
            fool.input(N, tree);
            int ans2 = fool.solve();
            if (ans1 != ans2) {
                break;
            }
        }
    } else {
        Solve solve;
        solve.input();
        solve.solve();
    }


    return 0;
}


Measured memory_bytes: 10112