# 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[to]) and cap > 0:
#                 d = self.__dfs(to, t, min(f, cap))

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

#                     _to, _cap, _rev = self.__g[to][rev]
#                     self.__g[to][rev] = (_to, _cap+d, _rev)

#                     return d
#         return 0


class Queue:
    def __init__(self):
        self.__count = 0
        self.__data = []

    def count(self) -> int:
        return self.__count

    def empty(self) -> bool:
        return self.__count == 0

    def front(self):
        if self.empty():
            raise Exception('empty')
        return self.__data[0]

    def dequeue(self):
        if self.empty():
            raise Exception('empty')
        res, self.__data = self.__data[0], self.__data[1:]
        self.__count -= 1
        return res

    def enqueue(self, v):
        self.__data.append(v)
        self.__count += 1


class Edge:
    def __init__(self, v: int, cap: int, rev: int):
        """
        :param v: to
        :param cap: capacity
        :param rev: revesed to
        """
        self.v = v
        self.cap = cap
        self.rev = rev

        self.flow = 0


class Graph:
    def __init__(self, num_v: int):
        """
        :param num_v: number of vertex
        """
        self.num_v = num_v
        self.level = [0] * num_v
        self.graph = [[] for _ in range(num_v)]

    def add_edge(self, u: int, v: int, cap: int):
        """add edge
        :param u: from
        :param v: to
        :param cap: capacity
        """
        forward = Edge(v, cap, len(self.graph[v]))
        back = Edge(u, 0, len(self.graph[u]))

        self.graph[u].append(forward)
        self.graph[v].append(back)

    def __bfs(self, s: int, t: int) -> bool:
        """Finds if more flow can be sent from s to t.
        Also assigns level to nodes.
        :param s: source
        :param t: sink
        :return: `True` if finds more flow can be sent from s to t.
        """
        self.level = [-1] * self.num_v
        self.level[s] = 0

        q = Queue()
        q.enqueue(s)
        while not q.empty():
            u = q.dequeue()

            for e in self.graph[u]:
                # not yet visited, and flow can be sent more
                if self.level[e.v] < 0 and e.flow < e.cap:
                    # level of v is level of its parent + 1
                    self.level[e.v] = self.level[u] + 1

                    q.enqueue(e.v)

        return self.level[t] >= 0

    def __send_flow(self,
                    u: int, flow: int, t: int, start: list = None) -> int:
        """send `flow` from `u` to `t`.
        :param u: from
        :param flow: flow
        :param t: to
        :param start: explored vertex
        :return: value of flow can be sent from u to t.
        """
        if u == t:
            return flow

        if start is None:
            start = [0] * (self.num_v + 1)

        while start[u] < len(self.graph[u]):
            e = self.graph[u][start[u]]

            if self.level[e.v] != self.level[u] + 1:
                # skip if level of e.v is not next to
                # u's one.
                start[u] += 1
                continue
            if not (e.flow < e.cap):
                # skip if flow cannot be sent more to
                # v.
                start[u] += 1
                continue

            cur_f = min(flow, e.cap - e.flow)
            tmp_f = self.__send_flow(e.v, cur_f, t, start)

            if tmp_f > 0:
                # add flow to current edge
                e.flow += tmp_f
                # subtract flow from reverse edge of current one.
                self.graph[e.v][e.rev].flow -= tmp_f

                return tmp_f

            start[u] += 1

        return 0

    def maximum_flow(self, s: int, t: int) -> int:
        """maximum flow from s to t.
        :param s: from
        :param t: to
        :return: maximum flow
        """
        if s == t:
            return 0

        max_flow = 0
        while self.__bfs(s, t):
            while True:
                flow = self.__send_flow(s, float('inf'), t)
                if flow == 0:
                    break
                max_flow += flow
        return max_flow


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 > 2:
        # 次数が 4 のものが 3 つ以上存在すれば OK
        return True
    if c4 < 2:
        # 次数が 4 のものが 1 つ以下なら NG
        return False

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

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

    return graph.maximum_flow(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')