#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define ll long long
#define pii pair<int,int>
#define INF 1000000000
#define all(x) (x.begin(), x.end())
#define IOS ios_base :: sync_with_stdio(0);cin.tie(0);cout.tie(0)
typedef vector<int> vi;

void testcases() {
	#ifndef ONLINE_JUDGE
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
	#endif
}

vi adj[112345];
int ans = 0;
int visited[112345];


void dfs(int v) {
	visited[v] = 1;
	ans++;
	for (auto x : adj[v]) {
		if (visited[x] == 1) continue;
		dfs(x);
	}
}

void solve() {
	int n,m;cin>>n>>m;
	int a,b;
	for (int i = 0; i < m; i++) {
		cin>>a>>b;
		adj[a].pb(b);
	}
	for (int k = 1; k <= n; k++) {
		for (int i = 1; i <= n; i++) {
			visited[i] = 0;
		}
		dfs(k);
	}
	
	
	cout << ans << '\n';

}	

int main() 
{
	//testcases();
	IOS;
    solve();
	return 0;

}
#include <bits/stdc++.h>

std::vector<std::string> split(const std::string& source, const char delim);

struct Node{
    explicit Node(const int nodeId)
    :node_id(nodeId){
    };

    int addNode(const std::shared_ptr<Node>& nodeSptr){
        child_node_sptr_list.emplace_back(nodeSptr);
        return 0;
    };

    int node_id;
    std::vector<std::weak_ptr<Node>> child_node_sptr_list;
};

int main(){
    std::string buffer;
    std::getline(std::cin, buffer);
    auto splitInput = split(buffer, ' ');
    const int NUM_CITY = std::stoi(splitInput[0]);
    const int NUM_ROOT = std::stoi(splitInput[1]);

    std::map<int, std::shared_ptr<Node>> nodeSptrList;
    for(int num = 0; num < NUM_CITY; ++num){
        nodeSptrList.emplace(num + 1, std::make_shared<Node>(num + 1));
        nodeSptrList[num + 1]->addNode(nodeSptrList[num + 1]);
    }

    for(int num = 0; num < NUM_ROOT; ++num){
        std::getline(std::cin, buffer);
        auto splitRootInfo = split(buffer, ' ');
        const int startNodeId = std::stoi(splitRootInfo[0]);
        const int endNodeId = std::stoi(splitRootInfo[1]);
        nodeSptrList[startNodeId]->addNode(nodeSptrList[endNodeId]);
    }

    std::map<std::pair<int, int>, int> uniqueRootList;
    for(const auto& startNodeSptrPair : nodeSptrList){
        std::queue<std::shared_ptr<Node>> nodeSptrQueue;
        nodeSptrQueue.emplace(startNodeSptrPair.second);

        while(!nodeSptrQueue.empty()){
            std::shared_ptr<Node> nodeSptr{nodeSptrQueue.front()};
            nodeSptrQueue.pop();

            for(auto it = nodeSptr->child_node_sptr_list.begin(); it != nodeSptr->child_node_sptr_list.end(); ++it){
                if(std::shared_ptr<Node> childNodeSptr = it->lock()){
                    const auto scanningRoot = std::make_pair(startNodeSptrPair.first, childNodeSptr->node_id);
                    if(uniqueRootList.find(scanningRoot) == uniqueRootList.end()){
                        nodeSptrQueue.emplace(childNodeSptr);
                        uniqueRootList.emplace(scanningRoot, 1);
                    }
                }
            }
        }
    }
    std::cout << uniqueRootList.size() << std::endl;

    return 0;
}

std::vector<std::string> split(const std::string& source, const char delim){
    std::vector<std::string> splitData;
    std::stringstream sstream(source);
    std::string itemBuffer;

    while(std::getline(sstream, itemBuffer, delim)){
        splitData.emplace_back(itemBuffer);
    }

    return splitData;
}