#include <bits/stdc++.h>
using namespace std;
template <typename Arg, typename... Args>
inline void input(Arg& arg, Args&... args) {
  cin >> arg;
  (void)(int[]){0, (void(cin >> args), 0)...};
}
template <typename Arg, typename... Args>
inline void printErr(Arg&& arg, Args&&... args) {
  cerr << arg;
  (void)(int[]){0, (void(cerr << " "
                              << "\033[1;41m"
                              << ","
                              << "\033[0m"
                              << " " << args),
                    0)...};
  cerr << '\n';
};
template <class T, class... U>
void dbg(const char* sdbg, T h, U... a) {
  cerr << "\033[1;31m"
       << "Debug: "
       << "\033[0m";
  cerr << sdbg;
  cerr << " "
       << "\033[1;41m"
       << "="
       << "\033[0m"
       << " ";
  printErr(h, a...);
}
template <class S, class T>
ostream& operator<<(ostream& os, const pair<S, T>& p) {
  return os << "pair(" << p.first << "\033[1;31m"
            << ", "
            << "\033[0m" << p.second << ")";
}
template <class T>
ostream& operator<<(ostream& os, const vector<T>& p) {
  os << "\033[1;32m"
     << "vector[ "
     << "\033[0m";
  for (auto& it : p)
    os << it << "\033[1;31m"
       << ", "
       << "\033[0m";
  return os << "\033[1;32m"
            << "]"
            << "\033[0m";
}
template <class T>
ostream& operator<<(ostream& os, const set<T>& p) {
  os << "\033[1;32m"
     << "set[ ";
  for (auto& it : p)
    os << it << "\033[1;31m"
       << ", "
       << "\033[0m";
  return os << "\033[1;32m"
            << "]"
            << "\033[0m";
}
template <class S, class T>
ostream& operator<<(ostream& os, const map<S, T>& p) {
  os << "\033[1;32m"
     << "map[ "
     << "\033[0m";
  for (auto& it : p)
    os << it << "\033[1;31m"
       << ", "
       << "\033[0m";
  return os << "\033[1;32m"
            << "]"
            << "\033[0m";
}
template <class T>
void dbgIter(const char* sdbg, T a, T b) {
  cerr << "\033[1;31m"
       << "Debug: "
       << "\033[0m";
  cerr << sdbg;
  cerr << "\033[1;31m"
       << " = "
       << "\033[0m";
  cerr << "[";
  for (T i = a; i != b; ++i) {
    if (i != a) cerr << ", ";
    cerr << *i;
  }
  cerr << "]\n";
}
template <typename T>
using min_heap = priority_queue<T, std::vector<T>, std::greater<T>>;
template <typename T>
using max_heap = priority_queue<T>;
template <typename T, typename S>
inline bool contains(map<T, S> map1, S value1) {
  return map1.find(value1) != map1.end();
}
template <typename T, typename S>
inline bool contains(T container1, S value1) {
  return container1.find(value1) != container1.end();
}
int32_t p[1010];
int32_t f(int32_t x) { return x == p[x] ? x : p[x] = f(p[x]); }
int32_t n, m;
void solve() {
  iota(begin(p), end(p), 0);
  cin >> n >> m;
  int32_t v1, v2;
  for (int64_t(i) = (0); (i) < (m); ++(i)) {
    cin >> v1 >> v2;
    p[f(v1)] = f(v2);
  }
  for (int64_t(i) = (2); (i) <= (n); ++(i))
    if (f(i) != f(1)) {
      cout << "no\n";
      return;
    }
  if ((n - 1) == m)
    cout << "yes\n";
  else
    cout << "no\n";
}
int32_t main() {
  std::ios_base::sync_with_stdio(false);
  cin.tie(nullptr);
  cout.tie(nullptr);
  cout.precision(20);
  cout << fixed;
  solve();
  return 0;
}
