#include <algorithm>
#include <cassert>
#include <cctype>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstring>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <vector>
#define rep(i, n) for (int i = 0; i < (int)(n); ++i)
//#define cerr if(false) cerr
#define show(...) cerr << #__VA_ARGS__ << " = ", debug(__VA_ARGS__);
using namespace std;
using ll = long long;
using pii = pair<int,int>;
template<typename T, typename S>
ostream &operator<<(ostream &os, pair<T, S> a){
    os << '(' << a.first << ',' << a.second << ')';
    return os;
}
template<typename T>
ostream &operator<<(ostream &os, vector<T> v){
    for(auto x:v)os << x << ' ';
    return os;
}
void debug(){cerr << '\n';}
template<typename H, typename... T>
void debug(H a, T... b){
    cerr << a;
    if(sizeof...(b))cerr << ", ";
    debug(b...);
}
class Articulation {
public:
    int V;
    vector<vector<int> > G;
    vector<int> ord;	//訪問時間
    vector<int> low; //low[u]はuから高々1個の後退辺を通ってたどりつけるノードのordの最小値
    vector<bool> visit; //訪問したかどうかのフラグ
    vector<bool> art; //関節点かどうかの判定
    // vector<vector<P> > edgeset;
    // stack<P> st;
    Articulation(int node_size) : V(node_size), G(V), ord(V, -1), low(V), visit(V, false), art(V, false){}
    void add_edge(int a,int b){
        G[a].push_back(b), G[b].push_back(a);
    }
    void dfs(int v,int p,int &k){
        visit[v] = true;
        ord[v] = low[v] = k++;
        int ct = 0;	//ノードvの次数
        for(int w : G[v]){
            // if(w != p && ord[w] < ord[v]) st.push(P(v, w));
            if(!visit[w]){
                ct++;
                dfs(w,v,k);
                low[v] = min(low[v],low[w]);	//子のノードのlowと比較する
                if(p >= 0 && ord[v] <= low[w]){
                    art[v] = true;
                }
                // if(low[w] >= ord[v]){
                //     edgeset.push_back(vector<P>());
                //     while(1){
                //         P p = st.top();
                //         st.pop();
                //         edgeset.back().push_back(p);
                //         if(p == P(v, w)) break;
                //     }
                // }
            }else if(w != p && ord[w] < low[v]){
                low[v] = ord[w];
            }
        }
        if(p == -1 && ct > 1){
            art[v] = true;	//根の次数が2以上なら根は関節点
        }
    }
    void solve(){
        for(int i = 0; i < V; i++){
            int k = 0;
            if(!visit[i]){
                dfs(i, -1, k);
            }
        }
    }
};

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n,m;
    cin >> n >> m;
    if(m < n + 2){
        cout << "No" << endl;
        return 0;
    }
    vector<vector<int>>g(n);
    rep(i,m){
        int a,b;
        cin >> a >> b;
        a--,b--;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    vector<int>d(n);
    rep(i,n)d[i] = (int) g[i].size();
    rep(i,n)if(d[i]%2){
        cout << "No" << endl;
        return 0;
    }
    rep(i,n)if(d[i] >= 6){
        cout << "Yes" << endl;
        return 0;
    }
    int cnt = 0;
    rep(i,n)if(d[i] == 4)cnt++;
    if(cnt <= 1){
        cout << "No" << endl;
        return 0;
    }
    if(cnt >= 3){
        cout << "Yes" << endl;
        return 0;
    }
    Articulation art(n);
    art.G = g;
    art.solve();
    rep(i,n){
        if(d[i] == 4)if(art.art[i]){
            cout << "Yes" << endl;
            return 0;
        }
    }
    cout << "No" << endl;
    return 0;
}

Measured memory_bytes: 16128