#include <cstdio>
#include <list>
#include <vector>
#include <queue>
#include <cstring>
#include <cstdlib>

using namespace std;

const int MAXN = 10000;
const int MAXM = 20000;

class Graph
{
	static const int MAX_VERTICES = MAXN * 2 + 2;
	static const int MAX_CAPACITY = (int)1;
	static const int MAX_EDGES = MAXM + MAXN * 2;

	struct edge_t
	{
		int to;
		int flow, capacity;
		int residual_capacity()const { return capacity - flow; }
	};

	static edge_t edges[2*MAX_EDGES];
	int edges_size;
	static vector<int> out_edges[MAX_VERTICES];
	static int first[MAX_VERTICES];
	static int dist[MAX_VERTICES];
	int source, sink, vertices;

	bool build_level_graph()
	{
		memset(dist,  -1, sizeof(*dist) * vertices);
		static int q[MAX_VERTICES];
		int q_head = 0, q_tail = 0;
		dist[source] = 0;
		q[q_tail++] = source;

		while (q_head < q_tail && dist[sink] == -1)
		{
			int vertex = q[q_head++];
			for (int edge : out_edges[vertex])
			{
				const edge_t &forward = edges[edge];
				if (dist[forward.to] == -1 && forward.residual_capacity() > 0)
				{
					q[q_tail++] = forward.to;
					dist[forward.to] = dist[vertex] + 1;
				}
			}
		}

		return dist[sink] != -1;
	}

	int find_blocking_flow(int vertex, int flow)
	{
		if (flow == 0)
		{
			return 0;
		}
		if (vertex == sink)
		{
			return flow;
		}

		for (; first[vertex] < (int)out_edges[vertex].size(); ++first[vertex])
		{
			edge_t &forward = edges[out_edges[vertex][first[vertex]]];
			if (dist[forward.to] == dist[vertex] + 1)
			{
				int augumenting = find_blocking_flow(forward.to, min(flow, forward.residual_capacity()));
				if (augumenting > 0)
				{
					edge_t &backward = edges[out_edges[vertex][first[vertex]] ^ 1];
					forward.flow += augumenting;
					backward.flow -= augumenting;
					return augumenting;
				}
			}
		}


		return false;
	}

public:
	Graph(int vertices, int source, int sink) : vertices(vertices), source(source), sink(sink), edges_size(0)
	{}
	void add_edge(int from, int to, int capacity)
	{
		edge_t forward = { to, 0, capacity };
		edge_t backward = { from, 0, 0 };
		out_edges[from].push_back(edges_size);
		edges[edges_size++] = forward;
		out_edges[to].push_back(edges_size);
		edges[edges_size++] = backward;
	}

	long long max_flow()
	{
		long long answer = 0;
		for (int i = 0; build_level_graph(); ++i)
		{
			memset(first, 0, sizeof(*first)*vertices);
			while(true) {
                int augmenting = find_blocking_flow(source, MAX_CAPACITY);
                if (augmenting > 0)
                {
                    answer += augmenting;
                }
                else
                {
                    break;
                }
			}
		}
		return answer;
	}
};

Graph::edge_t Graph::edges[2*Graph::MAX_EDGES] = {};
vector<int> Graph::out_edges[Graph::MAX_VERTICES] = {};
int Graph::first[Graph::MAX_VERTICES] = {};
int Graph::dist[Graph::MAX_VERTICES] = {};

void _1711()
{
	int n, m;
	scanf("%d%d", &n, &m);
	Graph graph(n, 0, n-1);
	for (int i = 0; i < m; ++i)
	{
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		--a; --b;
		graph.add_edge(a, b, c);
	}
	printf("%lld\n", graph.max_flow());
	exit(0);
}

int main()
{
	int n, m;
	//_1711();
	while (2 == scanf("%d%d", &n, &m))
	{
		Graph graph(2*n + 2, 0, 2*n + 1);
		for (int person = 1; person <= n; ++person)
		{
			graph.add_edge(0, person, 1);
			graph.add_edge(person+n, 2*n+1, 1);
		}
		for (int interest = 0; interest < m; ++interest)
		{
			int a, b;
			scanf("%d%d", &a, &b);
			++a; ++b;
			graph.add_edge(a, n + b, 1);
		}
		if (graph.max_flow() == n)
		{
			printf("YES\n");
		}
		else
		{
			printf("NO\n");
		}
	}


	return 0;
}
