#include <bits/stdc++.h>
template <typename T, int M, int N>
struct tuple_getter {
  static void get(std::istream &is, T &x) {
    is >> std::get<M>(x);
    tuple_getter<T, M + 1, N>::get(is, x);
  }
};
template <typename T, int N>
struct tuple_getter<T, N, N> {
  static void get(std::istream &is, T &x) { is >> std::get<N>(x); }
};
template <typename... Args>
std::istream &operator>>(std::istream &is, std::tuple<Args...> &t) {
  tuple_getter<std::tuple<Args...>, 0, sizeof...(Args) - 1>::get(is, t);
  return is;
}
template <typename T, typename U>
std::istream &operator>>(std::istream &is, std::pair<T, U> &p) {
  is >> p.first >> p.second;
  return is;
}
template <typename T>
std::istream &operator>>(std::istream &is, std::vector<T> &v) {
  for (T &x : v) is >> x;
  return is;
}
namespace sub {
template <typename T>
constexpr typename std::enable_if<std::is_integral<T>::value, T>::type
inf_sub() {
  return std::numeric_limits<T>::max() / 2 - 1000;
}
template <typename T>
constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
inf_sub() {
  return std::min(std::numeric_limits<T>::max() / 2 - 1000, T(1e50));
}
}  // namespace sub
template <typename T>
constexpr T inf() {
  static_assert(std::is_arithmetic<T>::value, "T must be arithmetic value");
  return sub::inf_sub<T>();
}
template <typename T>
constexpr T zero() {
  static_assert(std::is_arithmetic<T>::value, "T must be arithmetic value");
  return T(0);
}
const long double pi = acos(-1.0);
template <typename T, int M, int N>
struct tuple_printer {
  static void print(std::ostream &os, const T &x) {
    os << std::get<M>(x) << " ";
    tuple_printer<T, M + 1, N>::print(os, x);
  }
};
template <typename T, int N>
struct tuple_printer<T, N, N> {
  static void print(std::ostream &os, const T &x) { os << std::get<N>(x); }
};
template <typename... Args>
std::ostream &operator<<(std::ostream &os, const std::tuple<Args...> &t) {
  tuple_printer<std::tuple<Args...>, 0, sizeof...(Args) - 1>::print(os, t);
  return os;
}
template <typename T, typename U>
std::ostream &operator<<(std::ostream &os, const std::pair<T, U> &p) {
  os << p.first << " " << p.second;
  return os;
}
template <typename T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &v) {
  for (auto it = v.begin(); it != v.end(); ++it) {
    if (it != v.begin()) os << " ";
    os << *it;
  }
  return os;
}
template <typename T>
std::ostream &operator<<(std::ostream &os, const std::set<T> &v) {
  for (auto it = v.begin(); it != v.end(); ++it) {
    if (it != v.begin()) os << " ";
    os << *it;
  }
  return os;
}
template <typename T>
T &chmin(T &a, const T &b) {
  return a = std::min(a, b);
}
template <typename T>
T &chmax(T &a, const T &b) {
  return a = std::max(a, b);
}
class range {
  class index_type {
    int x;

   public:
    index_type(int x_) : x(x_) {}
    int operator*() const { return x; }
    bool operator!=(index_type &r) { return x < r.x; }
    void operator++() { ++x; }
  };
  index_type i, n;

 public:
  range(int n_) : i(0), n(n_) {}
  range(int i_, int n_) : i(i_), n(n_) {}
  index_type &begin() { return i; }
  index_type &end() { return n; }
};
using ll = long long;
using ld = long double;
using namespace std;
struct yes_no : std::numpunct<char> {
  string_type do_truename() const { return "Yes"; }
  string_type do_falsename() const { return "No"; }
};
struct Initialize {
  Initialize() {
    std::locale loc(std::locale(), new yes_no);
    std::cout << std::boolalpha << std::setprecision(11) << std::fixed;
    std::cout.imbue(loc);
  }
};
const Initialize initialize;
vector<int> g[128000];
bool visited[128000];
tuple<int, int, int> dfs(int v) {
  visited[v] = true;
  int max_a = 0, max_b = 0, max_c = 0;
  vector<int> sort_a, sort_ab;
  int n_child = 0;
  for (int u : g[v]) {
    if (visited[u]) continue;
    ++n_child;
    int a, b, c;
    tie(a, b, c) = dfs(u);
    chmax(max_a, a);
    chmax(max_a, b);
    chmax(max_b, a);
    chmax(max_c, c);
    sort_a.push_back(a);
    sort_ab.push_back(max(a, b));
  }
  max_a += max(0, n_child - 1);
  max_b += 1;
  sort(sort_a.begin(), sort_a.end());
  sort(sort_ab.begin(), sort_ab.end());
  int a_size = sort_a.size();
  if (a_size >= 2) {
    chmax(max_c, sort_a[a_size - 1] + sort_a[a_size - 2] + 1);
    chmax(max_c,
          sort_ab[a_size - 1] + sort_ab[a_size - 2] + int(g[v].size()) - 2);
  }
  chmax(max_c, max_a);
  chmax(max_c, max_b);
  return make_tuple(max_a, max_b, max_c);
}
int main() {
  int N;
  scanf("%d", &N);
  for (int i = 0; i < (int)(N - 1); i++) {
    int u, v;
    scanf("%d%d", &u, &v);
    --u;
    --v;
    g[u].push_back(v);
    g[v].push_back(u);
  }
  int a, b, c;
  tie(a, b, c) = dfs(0);
  cout << c << endl;
  return 0;
}
