# Неориентированный граф называется регулярным, если все его вершины имеют одинаковую степень.
# Для заданного списком ребер графа проверьте, является ли он регулярным.
# Формат входных данных
# Сначала вводятся числа n ( 1 ≤ n ≤ 100) – количество вершин в графе
# и m ( 0 ≤ m ≤ n(n - 1)/2) – количество ребер.
# Затем следует m пар чисел – ребра графа. Нумерация вершин с 0.
# Формат выходных данных
# Выведите «YES», если граф является регулярным, и «NO» в противном случае.

# Программа корректно работает на графах, в которых нет петель - ребер,
# выходящих из и возвращающихся в одну и ту же вершину. При наличии петель
# будет выдавать некорректный результат, т.к. при подсчете степени
# ребро-петля учитывается дважды, а данный словарь хранит множества,
# элементы в которых не повторяются.

n, m = (int(s) for s in input().split())

# Граф в виде словаря множеств смежных вершин:
graph = {i: set() for i in range(n)}

# Считываем ребра и добавляем в словарь:
for i in range(m):
    a, b = (int(s) for s in input().split())
    graph[a].add(b)
    graph[b].add(a)

# Если в графе не более 2 вершин, то они в любом случае будут иметь одинаковую степень.
if 1 <= n <= 2:
    print('YES')
    exit()

# Перед запуском цикла извлекаем из графа произвольную вершину
# и определяем количество смежных с ней вершин.
_, neighbours = graph.popitem()
check = len(neighbours)

# Перебираем все оставшиеся вершины графа и сравниваем количество смежных:
for vertex in graph:
    if len(graph[vertex]) != check:  # При первом же расхождении
        print('NO')  # завершаем программу.
        exit()

# Если мы перебрали вершины и не встретили расхождений в количестве смежных,
# то граф - регулярный.
print('YES')
