//#include <bits/stdc++.h>
#include<iostream>
#include<vector>
#include<map>
#include<math.h>

#define irep(i,n) for(int i = 0; i < (int)(n); i++)
#define irep2(i,a,n) for(int i = (int)(a); i <= (int)(n); i++)
#define irrep(i,n) for(int i = (int)(n-1); i > -1; i--)
#define irrep2(i,n,a) for(int i = (int)(n); i >= (int)(a); i--)

#define fi first
#define se second

using namespace std;

using ll = long long;
using v_int = vector<int>;
using v2_int = vector<v_int>;
using v_ll = vector<ll>;
using v2_ll = vector<v_ll>;
using v_string = vector<string>;
using v_bool = vector<bool>;
using v2_bool = vector<v_bool>;
using pii = pair<int, int>;
using mii = map<int, int>;

const double PI = 3.1415926535897932;
const int INF = (int)2e9;
const ll LINF = (ll)2e18;
const ll MOD = 1000000007;
const int dc[8] = {1, -1, 0,  0, 1, -1,  1, -1};
const int dr[8] = {0,  0, 1, -1, 1,  1, -1, -1};

template<typename T, typename U> inline
ostream& operator<<(ostream &o, pair<T,U> &p) {
    return o << "{" << p.first << "," << p.second << "}";
}
template<typename T> inline
istream& operator>>(istream &is, vector<T> &vec) {
    for(auto &v : vec) { is >> v; }
    return is;
}
template<typename T> inline
ostream& operator<<(ostream &os, vector<T> &vec) {
    for(auto &v : vec) { os << v << ",";}
    return os;
}
template<typename T> inline
ostream& operator<<(ostream &os, vector<vector<T> > &mat) {
    for(auto &row : mat) { os << row << endl; }
    return os;
}
template<typename T> inline
void chmin(T &a, T b) { a = min(a, b); }
template<typename T> inline
void chmax(T &a, T b) { a = max(a, b); }

class UnionFind {
public:
    v_int parents; 
    v_int size;
    int mx;

    // Constructor
    UnionFind(int n): parents(n), size(n), mx(n) {
        for(int i = 0; i < n; i++) { 
            parents[i] = i; 
            size[i] = 1;
        }
    }

    void init(int n) {
        parents.resize(n);
        size.resize(n);
        for(int i = 0; i < n; i++) { 
            parents[i] = i; 
            size[i] = 1;
        }
    }

    int root(int x) { 
        if (parents[x] == x) {
            return x;
        } else {
            return parents[x] = root(parents[x]);
        }
    }
    
    bool issame(int x, int y) { 
        return root(x) == root(y);
    }

    // Union(Unite, Merge)
    void merge(int x, int y) {
        x = root(x);
        y = root(y);
        if (x == y) return; 
        if (size[x] < size[y]) swap(x, y);
        size[x] += size[y];
        parents[y] = x;
    }


    int get_size(int x) {
        return size[root(x)];
    }
    
    void print() {
        for(size_t i = 0; i < parents.size(); i++) {
            cout << "parents[" << i << "]," << parents[i] << ",size," << size[i] << endl;
        }
    }
    
    v_int members(int x) {
        v_int mem;
        int r = root(x);
        for(int i = 0; i < mx; i++) { 
            if(root(i) == r) { mem.push_back(i); }
        }
        return mem;
    }

    v_int roots(void) {
        v_int r;
        for(int i = 0; i < mx; i++) {
            if(root(i) == i) { r.push_back(i); }
        }
        return r;
    }
};

int main(void)
{
    int n, m;
    cin >> n >> m;
    
    UnionFind uf(n);

    irep(i, m) {
        int a, b;
        cin >> a >> b;
        uf.merge(a-1, b-1);
    }

    mii group;

    irep(i, n) {
        //cout << uf.root(i) << endl;
        group[uf.root(i)]++;
    }
    
    int ans = 0;
    for(auto g : group) {
        chmax(ans, g.se);
    }

    cout << ans << endl;

    return 0;
} /*atcoder*/


Measured memory_bytes: 13912