#include <algorithm>
#include <chrono>
#include <cmath>
#include <functional>
#include <iostream>
#include <map>
#include <queue>
#include <tuple>
#include <utility>
#include <vector>

#define llong long long

using namespace std;
const int IINF = 2147483647;
const llong LLINF = 9223372036854775807;

// UnionFind
class UNF {
 private:
  int s;
  vector<int> tree, rank;
  int getP(int i) {
    if (tree[i] == -1)
      return i;
    else
      return tree[i] = getP(tree[i]);
  }

 public:
  UNF(int n) {
    s = n;
    tree.resize(s, -1);
    rank.resize(s, 1);
  }
  int size() { return s; }
  void connect(int a, int b) {
    a = getP(a);
    b = getP(b);
    if (a == b) return;
    if (rank[a] >= rank[b]) {
      tree[b] = a;
      rank[a] += rank[b];
    } else {
      tree[a] = b;
      rank[b] += rank[a];
    }
  }
  bool check(int a, int b) { return getP(a) == getP(b); }
};

// TimeLimit Checker
class TimeLimit {
 private:
  chrono::system_clock::time_point start, now;
  int limitms = 0;

 public:
  TimeLimit(int l) {
    now = start = chrono::system_clock::now();
    limitms = l;
  }
  bool check() {
    now = chrono::system_clock::now();
    bool ret = chrono::duration_cast<chrono::milliseconds>(now - start) <
               chrono::milliseconds(limitms);
    return ret;
  }
};

// Dijkstra
vector<llong> DJK(int n, int s, vector<vector<pair<int, llong>>> &E) {
  vector<pair<llong, bool>> V(n);
  for (int i = 0; i < n; i++) V[i] = make_pair(-1, false);
  V[s].first = 0;
  priority_queue<pair<llong, int>> Q;
  Q.push(make_pair(-V[s].first, s));
  while (!Q.empty()) {
    int m = Q.top().second;
    Q.pop();
    if (V[m].second) continue;
    V[m].second = true;
    for (pair<int, llong> p : E[m]) {
      int pd = p.first;
      llong plen = p.second;
      if (V[pd].first < 0) V[pd].first = LLINF;
      if (V[m].first + plen < V[pd].first) {
        V[pd].first = V[m].first + plen;
        Q.push(make_pair(-V[pd].first, pd));
      }
    }
  }
  vector<llong> ret(n);
  for (int i = 0; i < n; i++) ret[i] = V[i].first;
  return ret;
}

// Kruskal
vector<tuple<int, int, llong>> KRS(
    int n, vector<tuple<int, int, llong>> &E) {  //始点・終点・長さ
  UNF uf(n);
  priority_queue<tuple<llong, int, int>> Q;
  for (tuple<int, int, llong> tp : E) {
    Q.push(make_tuple(-get<2>(tp), get<0>(tp), get<1>(tp)));
  }
  vector<tuple<int, int, llong>> ret;
  while (!Q.empty()) {
    tuple<llong, int, int> tp = Q.top();
    Q.pop();
    int a = get<1>(tp), b = get<2>(tp);
    llong len = -get<0>(tp);
    if (!uf.check(a, b)) {
      ret.push_back(make_tuple(a, b, len));
      uf.connect(a, b);
    }
  }
  return ret;
}

//エラトステネスの篩
vector<int> SOE(int n) {
  vector<bool> isp(n + 1, true);
  int mp = 1;
  while (mp * mp <= n) {
    for (int i = mp + 1; i <= n + 1; i++) {
      if (i == n + 1) mp = n;  //次の素数がない場合
      if (isp[i]) {
        mp = i;
        break;
      }
    }
    for (int i = mp * 2; i <= n; i += mp) {
      isp[i] = false;
    }
  }
  vector<int> ret;
  for (int i = 2; i <= n; i++) {
    if (isp[i]) ret.push_back(i);
  }
  return ret;
}

//素因数分解
map<int, int> FIP(int n) {
  map<int, int> ret;
  int n0 = n;
  for (int i = 2; i * i <= n0 / 2; i++) {
    while (n % i == 0) {
      n /= i;
      ret[i]++;
    }
  }
  if (n > 1) ret[n]++;
  return ret;
}


int main(){
  UNF uf(13);
  uf.connect(1, 3);
  uf.connect(1, 5);
  uf.connect(1, 7);
  uf.connect(1, 8);
  uf.connect(1, 10);
  uf.connect(1, 12);
  uf.connect(4, 6);
  uf.connect(4, 9);
  uf.connect(4, 11);
  int x, y;
  cin >> x >> y;
  cout << (uf.check(x, y) ? "Yes" : "No");
  return 0;
}

Measured memory_bytes: 256