#include <bits/stdc++.h>
using namespace std;
inline bool SR(int &x) { return scanf("%d", &x) == 1; }
inline bool SR(long long &x) { return scanf("%lld", &x) == 1; }
inline bool SR(double &x) { return scanf("%lf", &x) == 1; }
inline bool SR(char *s) { return scanf("%s", s) == 1; }
inline bool RI() { return true; }
template <typename I, typename... T>
inline bool RI(I &x, T &...tail) {
  return SR(x) && RI(tail...);
}
inline void SP(const int x) { printf("%d", x); }
inline void SP(const long long x) { printf("%lld", x); }
inline void SP(const double x) { printf("%.16lf", x); }
inline void SP(const char *s) { printf("%s", s); }
inline void PL() { puts(""); }
template <typename I, typename... T>
inline void PL(const I x, const T... tail) {
  SP(x);
  if (sizeof...(tail)) putchar(' ');
  PL(tail...);
}
template <typename I>
void _DOING(const char *s, I &&x) {
  cerr << s << " = " << x << endl;
}
template <typename I, typename... T>
void _DOING(const char *s, I &&x, T &&...tail) {
  int c = 0;
  while (*s != ',' || c != 0) {
    if (*s == '(' || *s == '[' || *s == '{') c++;
    if (*s == ')' || *s == ']' || *s == '}') c--;
    cerr << *s++;
  }
  cerr << " = " << x << " , ";
  _DOING(s + 1, tail...);
}
inline int RAND() {
  static int x = 880301;
  return (x = x * 0xdefaced + 1) & 0x7fffffff;
}
const int INF = 0x3f3f3f3f;
const int MAX_N = 3000 + 10;
vector<int> G[MAX_N], G_rev[MAX_N];
int opt[MAX_N][3], opt_rev[MAX_N][3];
int dp[MAX_N][MAX_N], dp_rev[MAX_N][MAX_N];
int main() {
  int n, m;
  RI(n, m);
  while (m--) {
    int a, b;
    RI(a, b);
    a--, b--;
    G[a].push_back(b);
    G_rev[b].push_back(a);
  }
  for (int i = 0; i < int(n); i++) {
    queue<int> que;
    memset(dp[i], (0x3f), sizeof(dp[i]));
    dp[i][i] = 0;
    que.push(i);
    while (!que.empty()) {
      int u = que.front();
      que.pop();
      for (int v : G[u]) {
        if (dp[i][v] > dp[i][u] + 1) {
          dp[i][v] = dp[i][u] + 1;
          que.push(v);
        }
      }
    }
    priority_queue<pair<int, int> > pq;
    memset(opt[i], (-1), sizeof(opt[i]));
    for (int j = 0; j < int(n); j++)
      if (dp[i][j] != INF && j != i) pq.push(make_pair(dp[i][j], j));
    for (int j = 0; j < 3 && !pq.empty(); j++)
      opt[i][j] = pq.top().second, pq.pop();
  }
  for (int i = 0; i < int(n); i++) {
    queue<int> que;
    memset(dp_rev[i], (0x3f), sizeof(dp_rev[i]));
    dp_rev[i][i] = 0;
    que.push(i);
    while (!que.empty()) {
      int u = que.front();
      que.pop();
      for (int v : G_rev[u]) {
        if (dp_rev[i][v] > dp_rev[i][u] + 1) {
          dp_rev[i][v] = dp_rev[i][u] + 1;
          que.push(v);
        }
      }
    }
    priority_queue<pair<int, int> > pq;
    memset(opt_rev[i], (-1), sizeof(opt_rev[i]));
    for (int j = 0; j < int(n); j++)
      if (dp_rev[i][j] != INF && j != i) pq.push(make_pair(dp_rev[i][j], j));
    for (int j = 0; j < 3 && !pq.empty(); j++)
      opt_rev[i][j] = pq.top().second, pq.pop();
  }
  int ans = 0;
  tuple<int, int, int, int> ans_rd;
  for (int i = 0; i < int(n); i++) {
    for (int j = 0; j < int(n); j++) {
      if (j == i) continue;
      if (dp[i][j] == INF) continue;
      for (int a = 0; a < int(3); a++) {
        if (opt_rev[i][a] == -1 || opt_rev[i][a] == j) continue;
        for (int b = 0; b < int(3); b++) {
          if (opt[j][b] == -1 || opt[j][b] == i || opt[j][b] == opt_rev[i][a])
            continue;
          int t = dp[opt_rev[i][a]][i] + dp[i][j] + dp[j][opt[j][b]];
          if (t > ans) {
            ans = t;
            ans_rd = make_tuple(opt_rev[i][a], i, j, opt[j][b]);
          }
        }
      }
    }
  }
  PL(get<0>(ans_rd) + 1, get<1>(ans_rd) + 1, get<2>(ans_rd) + 1,
     get<3>(ans_rd) + 1);
  return 0;
}
