#xの根を求める

def find(x):

    if par[x] < 0:

        return x

    else:

        par[x] = find(par[x])

        return par[x]

#xとyの属する集合の併合

def unite(x,y):

    x = find(x)

    y = find(y)

    

    if x == y:

        return False

    else:

        #sizeの大きいほうがx

        if par[x] > par[y]:

            x,y = y,x

        par[x] += par[y]

        par[y] = x

        return True



#xとyが同じ集合に属するかの判定

def same(x,y):

    return find(x) == find(y)



#xが属する集合の個数

def size(x):

    return -par[find(x)]



n, m = list(map(int,input().split()))

#初期化

#根なら-size,子なら親の頂点

par = [-1]*n



for _ in range(m):

  a, b = list(map(int,input().split()))

  a -= 1

  b -= 1

  unite(a,b)

  

print((-min(par)))

  



  

              
# データ構造: Union Find (素集合データ構造)

#  前提

#    グラフ（頂点と辺からなる集合）上の各頂点が、どの連結成分に属しているかを管理するときに使う

#    具体的には、各連結成分ごとに適当な1点を親として、同じ連結成分に属する他の点が子になるように配置する

#  できること

#    1, ある頂点の親を返す (つまり、どの連結成分に属するかがわかる)

#    2, 新たな辺が与えられた時、必要なら連結成分の統合を行う



# 以下、事前準備。(本処理は42行目から)

# 上記1,2を実現する関数を作成する。



# 0, 前提

# par = [-1 for _ in range(n)]

#  配列parの要素par[i]には、

#    頂点iが子の場合に 親頂点の番号

#    頂点iが親の場合に 属する連結成分の頂点数を格納する。(区別のため負数として表記)

#  例: par = [2, 2, -3, -1, 5, -1]

#    点0,1,2からなる連結成分、点3からなる連結成分、点4,5からなる連結成分がある場合。



# 1, 頂点xの親を求める

def find(x):

    if par[x] < 0:

        return x

    else:

        par[x] = find(par[x])

        return par[x]

      

# 2, 頂点xとyが属する連結成分を結合する

def unite(x,y):

    x = find(x)

    y = find(y) 

    if x == y:

        return False

    else:

        #sizeの大きいほうがx

        if par[x] > par[y]:

            x,y = y,x

        par[x] += par[y]

        par[y] = x

        return True



# 以下、本処理

# 求めるもの：各連結成分の頂点数のうち、最大のもの

n, m = list(map(int,input().split()))

par = [-1 for _ in range(n)]

 

for _ in range(m): #各辺について

  a, b = list(map(int,input().split()))

  a -= 1

  b -= 1

  unite(a,b) #辺の両端(頂点aとb)が統合される

  

print((-min(par)))

# 各連結成分の頂点数は、配列parの中に負数として記録されている。

# 連結成分の最大の頂点数を求めたければ、そのminをとって-1倍すればよい。

# xの根を求める
def find(x):
    if par[x] < 0:
        return x
    else:
        par[x] = find(par[x])
        return par[x]


# xとyの属する集合の併合
def unite(x, y):
    x = find(x)
    y = find(y)
    if x == y:
        return False
    else:
        # sizeの大きいほうがx
        if par[x] > par[y]:
            x, y = y, x
        par[x] += par[y]
        par[y] = x
        return True


# xとyが同じ集合に属するかの判定
def same(x, y):
    return find(x) == find(y)


# xが属する集合の個数
def size(x):
    return -par[find(x)]


n, m = list(map(int, input().split()))
# 初期化
# 根なら-size,子なら親の頂点
par = [-1] * n
for _ in range(m):
    a, b = list(map(int, input().split()))
    a -= 1
    b -= 1
    unite(a, b)
print((-min(par)))

# データ構造: Union Find (素集合データ構造)
#  前提
#    グラフ（頂点と辺からなる集合）上の各頂点が、どの連結成分に属しているかを管理するときに使う
#    具体的には、各連結成分ごとに適当な1点を親として、同じ連結成分に属する他の点が子になるように配置する
#  できること
#    1, ある頂点の親を返す (つまり、どの連結成分に属するかがわかる)
#    2, 新たな辺が与えられた時、必要なら連結成分の統合を行う
# 以下、事前準備。(本処理は42行目から)
# 上記1,2を実現する関数を作成する。
# 0, 前提
# par = [-1 for _ in range(n)]
#  配列parの要素par[i]には、
#    頂点iが子の場合に 親頂点の番号
#    頂点iが親の場合に 属する連結成分の頂点数を格納する。(区別のため負数として表記)
#  例: par = [2, 2, -3, -1, 5, -1]
#    点0,1,2からなる連結成分、点3からなる連結成分、点4,5からなる連結成分がある場合。
# 1, 頂点xの親を求める
def find(x):
    if par[x] < 0:
        return x
    else:
        par[x] = find(par[x])
        return par[x]


# 2, 頂点xとyが属する連結成分を結合する
def unite(x, y):
    x = find(x)
    y = find(y)
    if x == y:
        return False
    else:
        # sizeの大きいほうがx
        if par[x] > par[y]:
            x, y = y, x
        par[x] += par[y]
        par[y] = x
        return True


# 以下、本処理
# 求めるもの：各連結成分の頂点数のうち、最大のもの
n, m = list(map(int, input().split()))
par = [-1 for _ in range(n)]
for _ in range(m):  # 各辺について
    a, b = list(map(int, input().split()))
    a -= 1
    b -= 1
    unite(a, b)  # 辺の両端(頂点aとb)が統合される
print((-min(par)))
# 各連結成分の頂点数は、配列parの中に負数として記録されている。
# 連結成分の最大の頂点数を求めたければ、そのminをとって-1倍すればよい。

-# xの根を求める +# データ構造: Union Find (素集合データ構造) +#  前提 +#    グラフ（頂点と辺からなる集合）上の各頂点が、どの連結成分に属しているかを管理するときに使う +#    具体的には、各連結成分ごとに適当な1点を親として、同じ連結成分に属する他の点が子になるように配置する +#  できること +#    1, ある頂点の親を返す (つまり、どの連結成分に属するかがわかる) +#    2, 新たな辺が与えられた時、必要なら連結成分の統合を行う +# 以下、事前準備。(本処理は42行目から) +# 上記1,2を実現する関数を作成する。 +# 0, 前提 +# par = [-1 for _ in range(n)] +#  配列parの要素par[i]には、 +#    頂点iが子の場合に 親頂点の番号 +#    頂点iが親の場合に 属する連結成分の頂点数を格納する。(区別のため負数として表記) +#  例: par = [2, 2, -3, -1, 5, -1] +#    点0,1,2からなる連結成分、点3からなる連結成分、点4,5からなる連結成分がある場合。 +# 1, 頂点xの親を求める -# xとyの属する集合の併合 +# 2, 頂点xとyが属する連結成分を結合する -# xとyが同じ集合に属するかの判定 -def same(x, y): -    return find(x) == find(y) - - -# xが属する集合の個数 -def size(x): -    return -par[find(x)] - - +# 以下、本処理 +# 求めるもの：各連結成分の頂点数のうち、最大のもの -# 初期化 -# 根なら-size,子なら親の頂点 -par = [-1] * n -for _ in range(m): +par = [-1 for _ in range(n)] +for _ in range(m):  # 各辺について -    unite(a, b) +    unite(a, b)  # 辺の両端(頂点aとb)が統合される +# 各連結成分の頂点数は、配列parの中に負数として記録されている。 +# 連結成分の最大の頂点数を求めたければ、そのminをとって-1倍すればよい。