#include <bits/stdc++.h>
#pragma GCC optimize "O3"
#pragma GCC optimize "unroll-loops"
using namespace std;
using uint = unsigned;
using ll = long long;
using ull = unsigned long long;
using vi = vector<int>;
using vvi = vector<vi>;
using vl = vector<ll>;
using vvl = vector<vl>;
using vd = vector<double>;
using vvd = vector<vd>;
using vs = vector<string>;
template <typename T1, typename T2>
ostream& operator<<(ostream& os, const pair<T1, T2>& p) {
  return os << '(' << p.first << ',' << p.second << ')';
}
template <typename Tuple>
void print_tuple(ostream&, const Tuple&) {}
template <typename Car, typename... Cdr, typename Tuple>
void print_tuple(ostream& os, const Tuple& t) {
  print_tuple<Cdr...>(os, t);
  os << (sizeof...(Cdr) ? "," : "") << get<sizeof...(Cdr)>(t);
}
template <typename... Args>
ostream& operator<<(ostream& os, const tuple<Args...>& t) {
  print_tuple<Args...>(os << '(', t);
  return os << ')';
}
template <typename Ch, typename Tr, typename C>
basic_ostream<Ch, Tr>& operator<<(basic_ostream<Ch, Tr>& os, const C& c) {
  os << '[';
  for (auto i = begin(c); i != end(c); ++i)
    os << (i == begin(c) ? "" : " ") << *i;
  return os << ']';
}
constexpr int INF = 1e9;
constexpr int MOD = 1e9 + 7;
constexpr double EPS = 1e-9;
struct Edge {
  int src, dst;
  Edge() {}
  Edge(int s, int d) : src(s), dst(d) {}
};
using Graph = vector<vector<Edge>>;
bool is_unique(int a, int b, int c, int d) {
  int t[] = {a, b, c, d};
  sort(begin(t), end(t));
  return unique(begin(t), end(t)) - begin(t) == 4;
}
int main() {
  for (int n, m; cin >> n >> m && n | m;) {
    Graph g(n);
    for (int i = int(0); i < int(m); i++) {
      int u, v;
      cin >> u >> v;
      u--, v--;
      g[u].emplace_back(u, v);
    }
    vvi d(n, vi(n, INF));
    for (int i = int(0); i < int(n); i++) {
      d[i][i] = 0;
      queue<int> q;
      q.push(i);
      while (q.size()) {
        int u = q.front();
        q.pop();
        for (auto e : g[u]) {
          int v = e.dst;
          if (d[i][v] == INF) {
            d[i][v] = d[i][u] + 1;
            q.push(v);
          }
        }
      }
    }
    vector<vector<tuple<int, int>>> d1(n), d2(n);
    for (int i = int(0); i < int(n); i++)
      for (int j = int(0); j < int(n); j++)
        if (d[i][j] != INF) {
          d1[j].emplace_back(d[i][j], i);
          d2[i].emplace_back(d[i][j], j);
        }
    for (int i = int(0); i < int(n); i++) {
      sort(begin(d1[i]), end(d1[i]), greater<tuple<int, int>>());
      sort(begin(d2[i]), end(d2[i]), greater<tuple<int, int>>());
    }
    tuple<int, int, int, int, int> res(-1, 0, 0, 0, 0);
    for (int i = int(0); i < int(n); i++)
      for (int j = int(0); j < int(n); j++)
        if (i != j && d[i][j] != INF) {
          for (int k = int(0); k < int(min<int>(d1[i].size(), 3)); k++)
            for (int l = int(0); l < int(min<int>(d2[j].size(), 3)); l++) {
              int u, v, x, y;
              tie(x, u, y, v) = tuple_cat(d1[i][k], d2[j][l]);
              if (!is_unique(u, i, j, v)) continue;
              res = max(res, make_tuple(x + d[i][j] + y, u, i, j, v));
            }
        }
    printf("%d %d %d %d\n", get<1>(res) + 1, get<2>(res) + 1, get<3>(res) + 1,
           get<4>(res) + 1);
  }
}
