#include <bits/stdc++.h>
using namespace std;
void init() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);
}
int random(int min, int max) {
  static bool first = true;
  if (first) {
    srand(time(NULL));
    first = false;
  }
  return min + rand() % ((max + 1) - min);
}
class GraphAdj {
 public:
  int vertices;
  int edges;
  vector<int> *adjL;
  GraphAdj(int n) {
    this->vertices = n;
    this->edges = 0;
    this->adjL = new vector<int>[n];
  }
  GraphAdj(int n, int e) {
    this->vertices = n;
    this->edges = e;
    this->adjL = new vector<int>[n];
  }
  void addEdge(int x, int y) { adjL[x].push_back(y); }
  void printGraph() {
    for (int i = 0; i < vertices; ++i) {
      for (int x : adjL[i]) {
        cout << i + 1 << " " << x + 1 << '\n';
      }
    }
  }
  vector<vector<int>> bfs(int start) {
    vector<vector<int>> res;
    vector<bool> visited(vertices, 0);
    queue<int> q;
    visited[start] = 1;
    q.push(start);
    while (!q.empty()) {
      int count = q.size();
      vector<int> t;
      while (count--) {
        int top = q.front();
        q.pop();
        t.push_back(top);
        for (int x : adjL[top]) {
          if (!visited[x]) {
            visited[x] = 1;
            q.push(x);
          }
        }
      }
      res.push_back(t);
    }
    return res;
  }
  void dfsSource(int s, vector<bool> &visited, vector<int> &v) {
    visited[s] = 1;
    v.push_back(s);
    for (int x : adjL[s]) {
      if (!visited[x]) dfsSource(x, visited, v);
    }
  }
  void dfsAll(vector<int> &v) {
    vector<bool> visited(vertices, 0);
    for (int i = 0; i < vertices; ++i) {
      if (!visited[i]) dfsSource(i, visited, v);
    }
  }
  void dfsTimeStamps(int s, int &time, vector<int> &in, vector<int> &out,
                     vector<bool> &visited) {
    visited[s] = 1;
    in[s] = ++time;
    for (int x : adjL[s]) {
      if (!visited[x]) dfsTimeStamps(x, time, in, out, visited);
    }
    out[s] = ++time;
  }
  int findMotherVertex() {
    vector<int> v;
    vector<bool> visited(vertices, 0);
    int ans = 0;
    for (int i = 0; i < vertices; ++i) {
      if (!visited[i]) {
        dfsSource(i, visited, v);
        ans = i;
      }
    }
    v.clear();
    fill(visited.begin(), visited.end(), 0);
    dfsSource(ans, visited, v);
    for (int i = 0; i < vertices; ++i) {
      if (!visited[i]) return -1;
    }
    return ans;
  }
  int MinNumEdges_or_ShortPthBw2Vert(int src, int dest) {
    vector<bool> visited(vertices, 0);
    vector<int> dist(vertices, 0);
    queue<int> q;
    dist[src] = 0;
    visited[src] = 1;
    q.push(src);
    while (!q.empty()) {
      int top = q.front();
      q.pop();
      for (int x : adjL[top]) {
        if (!visited[x]) {
          dist[x] = dist[top] + 1;
          q.push(x);
          visited[x] = 1;
        }
      }
    }
    return dist[dest];
  }
  bool findDirCycleHelper(int s, vector<bool> &visited,
                          vector<bool> &recStack) {
    visited[s] = 1;
    recStack[s] = 1;
    for (int x : adjL[s]) {
      if ((!visited[x]) and findDirCycleHelper(x, visited, recStack)) {
        return 1;
      } else if (recStack[x]) {
        return 1;
      }
    }
    recStack[s] = 0;
    return 0;
  }
  bool findDirCycle() {
    vector<bool> visited(vertices, 0), recStack(vertices, 0);
    for (int i = 0; i < vertices; ++i)
      if (!visited[i] and findDirCycleHelper(i, visited, recStack)) return 1;
    return 0;
  }
  bool findUnDirCycleHelper(int s, vector<bool> &visited, int par) {
    visited[s] = 1;
    for (int x : adjL[s]) {
      if (visited[x] and x != par) {
        return 1;
      }
      if ((!visited[x]) and findUnDirCycleHelper(x, visited, s)) {
        return 1;
      }
    }
    return 0;
  }
  bool findUnDirCycle() {
    vector<bool> visited(vertices, 0);
    for (int i = 0; i < vertices; ++i) {
      if (!visited[i] and findUnDirCycleHelper(i, visited, -1)) {
        return 1;
      }
    }
    return 0;
  }
  void topSortHelper(int s, vector<bool> &visited, stack<int> &st) {
    visited[s] = 1;
    for (int x : adjL[s]) {
      if (!visited[x]) {
        topSortHelper(x, visited, st);
      }
    }
    st.push(s);
  }
  vector<int> topSort() {
    vector<bool> visited(vertices, 0);
    vector<int> v;
    stack<int> st;
    for (int i = 0; i < vertices; ++i) {
      if (!visited[i]) {
        topSortHelper(i, visited, st);
      }
    }
    while (!st.empty()) {
      v.push_back(st.top());
      st.pop();
    }
    return v;
  }
  int findUnDirCycleNLengthHelper(int s, int par, int n,
                                  vector<bool> &visited) {
    visited[s] = 1;
    int count = 0;
    if (n == 0) {
      visited[s] = 0;
      if (find(adjL[s].begin(), adjL[s].end(), par) != adjL[s].end()) {
        count++;
      }
      return count;
    }
    for (int x : adjL[s]) {
      if (!visited[x]) {
        count += findUnDirCycleNLengthHelper(x, par, n - 1, visited);
      }
    }
    visited[s] = 0;
    return count;
  }
  int findUnDirCycleNLength(int n) {
    vector<bool> visited(vertices, 0);
    int count = 0;
    for (int i = 0; i < vertices - (n - 1); ++i) {
      count += findUnDirCycleNLengthHelper(i, i, n - 1, visited);
      visited[i] = 1;
    }
    return count / 2;
  }
  pair<int, vector<int>> BestFirstSearch(int src, int dest,
                                         vector<vector<int>> &dist) {
    int cost = 0;
    vector<bool> visited(vertices, 0);
    priority_queue<pair<int, int>, vector<pair<int, int>>,
                   greater<pair<int, int>>>
        pq;
    pq.push({0, src});
    visited[src] = 1;
    vector<int> v;
    while (!pq.empty()) {
      pair<int, int> p = pq.top();
      pq.pop();
      cost += p.first;
      v.push_back(p.second);
      if (p.second == dest) break;
      for (int x : adjL[p.second]) {
        if (!visited[x]) {
          visited[x] = 1;
          pq.push({dist[p.second][x], x});
        }
      }
    }
    return {cost, v};
  }
  vector<int> KahnsTopSort() {
    vector<int> indegree(vertices, 0), res;
    for (int i = 0; i < vertices; ++i) {
      for (int x : adjL[i]) indegree[x]++;
    }
    queue<int> q;
    int count = 0;
    for (int i = 0; i < vertices; ++i) {
      if (indegree[i] == 0) {
        q.push(i);
      }
    }
    while (!q.empty()) {
      int top = q.front();
      q.pop();
      res.push_back(top);
      for (int x : adjL[top]) {
        if (--indegree[x] == 0) q.push(x);
      }
      count++;
    }
    if (count != vertices) {
      return {};
    }
    return res;
  }
  void AlienDictionary(vector<string> &words, int MaxChar) {
    GraphAdj g(MaxChar);
    int n = words.size();
    string word1, word2;
    for (int i = 0; i < n - 1; ++i) {
      word1 = words[i], word2 = words[i + 1];
      for (int j = 0; j < min(word1.size(), word2.size()); ++j) {
        if (word1[j] != word2[j]) {
          g.addEdge(word1[j] - 'a', word2[j] - 'a');
          break;
        }
      }
    }
    vector<int> v = g.topSort();
    for (int x : v) cout << (char)('a' + x) << " ";
  }
};
class GraphMat {
 public:
  int vertices;
  int edges;
  vector<vector<int>> adjMat;
  GraphMat(int n) {
    this->vertices = n;
    this->edges = 0;
    this->adjMat.resize(n, vector<int>(n, 0));
  }
  GraphMat(int n, int e) {
    this->vertices = n;
    this->edges = e;
    this->adjMat.resize(n, vector<int>(n, 0));
  }
  void addEdge(int x, int y) { this->adjMat[x][y] = 1; }
  void printGraph() {
    for (int i = 0; i < vertices; ++i) {
      for (int j = 0; j < vertices; ++j) {
        if (adjMat[i][j]) cout << i + 1 << " " << j + 1 << '\n';
      }
    }
  }
  vector<vector<int>> bfs(int start) {
    vector<vector<int>> res;
    vector<bool> visited(vertices, 0);
    queue<int> q;
    visited[start] = 1;
    q.push(start);
    while (!q.empty()) {
      int count = q.size();
      vector<int> t;
      while (count--) {
        int top = q.front();
        q.pop();
        t.push_back(top);
        for (int i = 0; i < adjMat[top].size(); ++i) {
          if (!visited[i] and adjMat[top][i]) {
            visited[i] = 1;
            q.push(i);
          }
        }
      }
      res.push_back(t);
    }
    return res;
  }
  void dfsSource(int s, vector<bool> &visited, vector<int> &v) {
    visited[s] = 1;
    v.push_back(s);
    for (int i = 0; i < vertices; ++i) {
      if (!visited[i] and adjMat[s][i]) dfsSource(i, visited, v);
    }
  }
  void dfsAll(vector<int> &v) {
    vector<bool> visited(vertices, 0);
    for (int i = 0; i < vertices; ++i) {
      if (!visited[i]) dfsSource(i, visited, v);
    }
  }
  int findMotherVertex() {
    vector<int> v;
    vector<bool> visited(vertices, 0);
    int ans = 0;
    for (int i = 0; i < vertices; ++i) {
      if (!visited[i]) {
        dfsSource(i, visited, v);
        ans = i;
      }
    }
    v.clear();
    fill(visited.begin(), visited.end(), 0);
    dfsSource(ans, visited, v);
    for (int i = 0; i < vertices; ++i) {
      if (!visited[i]) return -1;
    }
    return ans;
  }
  int MinNumEdges_or_ShortPthBw2Vert(int src, int dest) {
    vector<bool> visited(vertices, 0);
    vector<int> dist(vertices, 0);
    queue<int> q;
    dist[src] = 0;
    visited[src] = 1;
    q.push(src);
    while (!q.empty()) {
      int top = q.front();
      q.pop();
      for (int i = 0; i < adjMat[top].size(); ++i) {
        if (!visited[i] and adjMat[top][i]) {
          dist[i] = dist[top] + 1;
          q.push(i);
          visited[i] = 1;
        }
      }
    }
    return dist[dest];
  }
  bool findDirCycleHelper(int s, vector<bool> &visited,
                          vector<bool> &recStack) {
    visited[s] = 1;
    recStack[s] = 1;
    for (int x = 0; x < adjMat[s].size(); ++x) {
      if ((!visited[x] and adjMat[s][x]) and
          findDirCycleHelper(x, visited, recStack)) {
        return 1;
      } else if (adjMat[s][x] and recStack[x]) {
        return 1;
      }
    }
    recStack[s] = 0;
    return 0;
  }
  bool findDirCycle() {
    vector<bool> visited(vertices, 0), recStack(vertices, 0);
    for (int i = 0; i < vertices; ++i)
      if (!visited[i] and findDirCycleHelper(i, visited, recStack)) return 1;
    return 0;
  }
  bool findUnDirCycleHelper(int s, vector<bool> &visited, int par) {
    visited[s] = 1;
    for (int x = 0; x < adjMat[s].size(); ++x) {
      if (visited[x] and adjMat[s][x] and x != par) {
        return 1;
      }
      if ((!visited[x]) and adjMat[s][x] and
          findUnDirCycleHelper(x, visited, s)) {
        return 1;
      }
    }
    return 0;
  }
  bool findUnDirCycle() {
    vector<bool> visited(vertices, 0);
    for (int i = 0; i < vertices; ++i) {
      if (!visited[i] and findUnDirCycleHelper(i, visited, -1)) {
        return 1;
      }
    }
    return 0;
  }
  void topSortHelper(int s, vector<bool> &visited, stack<int> &st) {
    visited[s] = 1;
    for (int x = 0; x < adjMat[s].size(); ++x) {
      if (!visited[x] and adjMat[s][x]) {
        topSortHelper(x, visited, st);
      }
    }
    st.push(s);
  }
  vector<int> topSort() {
    vector<bool> visited(vertices, 0);
    vector<int> v;
    stack<int> st;
    for (int i = 0; i < vertices; ++i) {
      if (!visited[i]) {
        topSortHelper(i, visited, st);
      }
    }
    while (!st.empty()) {
      v.push_back(st.top());
      st.pop();
    }
    return v;
  }
  int findUnDirCycleNLengthHelper(int s, int par, int n,
                                  vector<bool> &visited) {
    visited[s] = 1;
    int count = 0;
    if (n == 0) {
      visited[s] = 0;
      if (adjMat[s][par]) {
        count++;
      }
      return count;
    }
    for (int x = 0; x < adjMat[s].size(); ++x) {
      if (!visited[x] and adjMat[s][x]) {
        count += findUnDirCycleNLengthHelper(x, par, n - 1, visited);
      }
    }
    visited[s] = 0;
    return count;
  }
  int findUnDirCycleNLength(int n) {
    vector<bool> visited(vertices, 0);
    int count = 0;
    for (int i = 0; i < vertices - (n - 1); ++i) {
      count += findUnDirCycleNLengthHelper(i, i, n - 1, visited);
      visited[i] = 1;
    }
    return count / 2;
  }
  bool findNegCycleFloydWarshall(vector<vector<int>> &dist) {
    for (int k = 0; k < vertices; ++k) {
      for (int i = 0; i < vertices; ++i) {
        for (int j = 0; j < vertices; ++j) {
          if (dist[i][k] + dist[k][j] < dist[i][j]) {
            dist[i][j] = dist[i][k] + dist[k][j];
          }
        }
      }
    }
    for (int i = 0; i < vertices; ++i) {
      if (dist[i][i] < 0) return 1;
    }
    return 0;
  }
  vector<int> KahnsTopSort() {
    vector<int> indegree(vertices, 0), res;
    for (int i = 0; i < vertices; ++i) {
      for (int x = 0; x < vertices; ++x)
        if (adjMat[i][x]) indegree[x]++;
    }
    queue<int> q;
    int count = 0;
    for (int i = 0; i < vertices; ++i) {
      if (indegree[i] == 0) {
        q.push(i);
      }
    }
    while (!q.empty()) {
      int top = q.front();
      q.pop();
      res.push_back(top);
      for (int x = 0; x < adjMat[top].size(); ++x) {
        if (adjMat[top][x])
          if (--indegree[x] == 0) q.push(x);
      }
      count++;
    }
    if (count != vertices) {
      return {};
    }
    return res;
  }
  pair<int, vector<int>> BestFirstSearch(int src, int dest,
                                         vector<vector<int>> &dist) {
    int cost = 0;
    vector<bool> visited(vertices, 0);
    priority_queue<pair<int, int>, vector<pair<int, int>>,
                   greater<pair<int, int>>>
        pq;
    pq.push({0, src});
    visited[src] = 1;
    vector<int> v;
    while (!pq.empty()) {
      pair<int, int> p = pq.top();
      pq.pop();
      cost += p.first;
      v.push_back(p.second);
      if (p.second == dest) break;
      for (int x = 0; x < vertices; ++x) {
        if (!visited[x] and adjMat[p.second][x]) {
          visited[x] = 1;
          pq.push({dist[p.second][x], x});
        }
      }
    }
    return {cost, v};
  }
};
void dfs(GraphAdj g, int root, vector<int> &dp, vector<bool> &visited) {
  visited[root] = 1;
  for (int x : g.adjL[root]) {
    if (!visited[x]) {
      dfs(g, x, dp, visited);
      dp[root] = max(dp[root], dp[x] + 1);
    }
  }
}
int maxDiameter(int root, GraphAdj g, int no, vector<bool> &visited, int &h) {
  visited[root] = 1;
  int ans1 = 0, ans2 = 0;
  for (int x : g.adjL[root]) {
    if (!visited[x] and x != no) {
      int ans = maxDiameter(x, g, no, visited, h);
      if (ans > ans1)
        ans2 = ans1, ans1 = ans;
      else if (ans > ans2)
        ans2 = ans;
    }
  }
  h = max(h, ans1 + ans2);
  return 1 + max(ans1, ans2);
}
int solve(GraphAdj g, int root) {
  int n = g.vertices;
  vector<int> dp(n, 0);
  vector<bool> visited(n, 0);
  dfs(g, root, dp, visited);
  int path1 = 0, path2 = 0;
  int pOne_Idx = -1, pSec_Idx = -1;
  int sum = 0;
  for (int x : g.adjL[root]) {
    if (pOne_Idx == -1) {
      pOne_Idx = x;
      path1 = dp[x];
    } else if (dp[pOne_Idx] < dp[x]) {
      pOne_Idx = x;
      path1 = dp[x];
    }
  }
  for (int x : g.adjL[root]) {
    if (pSec_Idx == -1) {
      if (pOne_Idx != x) {
        pSec_Idx = x;
        path2 = dp[x];
      }
    } else if (x != pOne_Idx and dp[pSec_Idx] < dp[x]) {
      pSec_Idx = x;
      path2 = dp[x];
    }
  }
  if (pOne_Idx == -1 or pSec_Idx == -1) {
    return 0;
  }
  int ans = 0;
  for (int x : g.adjL[root]) {
    int h = 0, k = 0;
    fill(visited.begin(), visited.end(), 0);
    maxDiameter(root, g, x, visited, h);
    int maxSeq = h;
    fill(visited.begin(), visited.end(), 0);
    maxDiameter(x, g, root, visited, k);
    int maxSeqChild = k;
    ans = max(ans, maxSeqChild * maxSeq);
  }
  return max(ans, max((path1 + 1) * path2, path1 * (path2 + 1)));
}
int main() {
  init();
  int n, e, x, y;
  cin >> n;
  e = n - 1;
  GraphAdj g(n, e);
  while (e--) {
    cin >> x >> y;
    g.addEdge(x - 1, y - 1);
    g.addEdge(y - 1, x - 1);
  }
  if (n <= 3) {
    cout << 0 << '\n';
    return 0;
  }
  int root = 0;
  for (int i = 0; i < n; ++i) {
    if (g.adjL[i].size() > g.adjL[root].size()) {
      root = i;
    }
  }
  vector<int> roots;
  for (int i = 0; i < n; ++i) {
    if (g.adjL[i].size() == g.adjL[root].size()) roots.push_back(i);
  }
  int ans = 0;
  for (int i = 0; i < n; ++i) {
    ans = max(solve(g, i), ans);
  }
  cout << ans << '\n';
  return 0;
}
