class Graph:
    def __init__(self, V: int):
        self.__V = V
        self.__g = [[] for _ in range(V)]
        self.__used = [False] * V

    def add_edge(self, u: int, v: int, cap: int):
        self.__g[u].append((v, cap, len(self.__g[v])))
        self.__g[v].append((u, 0, len(self.__g[u])-1))

    def ford_fulkerson(self, s: int, t: int)->int:
        flow = 0
        while True:
            self.__used = [False] * self.__V
            f = self.__dfs(s, t, float('inf'))
            if f == 0:
                break
            flow += f
        return flow

    def __dfs(self, v: int, t: int, f: int)->int:
        if v == t:
            return f
        self.__used[v] = True

        for i, (to, cap, rev) in enumerate(self.__g[v]):
            if (not self.__used[v]) and cap > 0:
                d = self.__dfs(to, t, min(f, cap))

                if d > 0:
                    self.__g[v][i] = (to, cap-d, rev)
                    self.__g[to][rev][1] += d
                    return d
        return 0


def three_circuits(N: int, M: int, edges: list)->bool:
    d = [0] * N

    for u, v in edges:
        d[u-1] += 1
        d[v-1] += 1

    if any(v & 1 == 1 for v in d):
        # euler 閉路でないなら NG
        return False
    if any(v >= 6 for v in d):
        # 次数が 6 以上のものがあれば OK
        return True

    c4 = d.count(4)
    if c4 >= 3:
        # 次数が 4 のものが 3 つ以上存在すれば OK
        return True
    if c4 < 2:
        # 次数が 4 のものが 1 つ以下なら NG
        return False

    # 次数が 4 のものが 2 つならその二つの頂点間にパスが二つ
    # の時のみ OK
    graph = Graph(N)
    for u, v in edges:
        graph.add_edge(u, v, 1)

    u = d.index(4)
    v = d.index(4, start=u+1)

    return graph.ford_fulkerson(u, v) == 2


if __name__ == "__main__":
    M = 0
    N, M = map(int, input().split())
    edges = [tuple(map(int, input().split())) for _ in range(M)]
    yes = three_circuits(N, M, edges)
    print('Yes' if yes else 'No')


### FIXED CODE ###

def has_circuit(g: list, s: int, ng: int) -> bool:
    stack = []
    stack.append((s, -1))  # (現在の頂点, 親)

    while len(stack) > 0:
        u, p = stack.pop()

        if u == s and p >= 0:
            return True

        for v in g[u]:
            if v == ng:
                continue
            if v == p:
                continue
            stack.append((v, u))
    return False


def three_circuit(N: int, M: int, edges: list) -> bool:
    g = [[] for _ in range(N)]

    for u, v in edges:
        g[u-1].append(v-1)
        g[v-1].append(u-1)

    dims = [len(p) for p in g]

    if not all(d % 2 == 0 for d in dims):
        # オイラー閉路でない
        return False

    if max(dims) >= 6:
        # 次元数が 6 以上の頂点があるならそいつを利用して
        # 3 つのサーキットが作れる。
        return True

    # 次元数 4 の頂点集合
    vertexes = [v for v in range(N) if dims[v] == 4]

    if len(vertexes) >= 3:
        # 次元数 4 の頂点が 3 つ以上存在するなら OK
        return True

    if len(vertexes) == 2:
        # 次元数 4 の頂点が 2 つのみ存在する場合、ありうるのは、この
        # 2 頂点の間にパスが 4 つある場合と 2 つある場合。
        # 前者は図を書けばすぐわかるが高々 2 つのサーキットしか作れな
        # い。後者の場合は、この 2 頂点を含むサーキットが 1 つとそれ
        # ぞれの頂点しか含まないサーキットが 1 つずつ、計 3 つ作れる。

        # 次数 4 の頂点からスタートしてほかの次数 4 の頂点に出会わずに
        # 帰ってこれるパスが存在すれば次数 4 の頂点間にはパスがちょうど
        # 2 つとなる。
        return has_circuit(g, vertexes[0], vertexes[1])
    # 残りは 次数 4 の点が 1 つ、あるいはすべての頂点の次数が 2 となる。
    # 前者の場合、高々 2 つのサーキット、後者の場合は高々 1 つのサーキッ
    # トしか作れないのは自明。
    return False


if __name__ == "__main__":
    M = 0
    N, M = map(int, input().split())
    edges = [tuple(int(s) for s in input().split()) for _ in range(M)]

    yes = three_circuit(N, M, edges)
    print('Yes' if yes else 'No')