#if defined(__GNUC__) && defined(__x86_64__)# pragma GCC optimize("O3")# pragma GCC optimize("Ofast")# pragma GCC optimize("unroll-loops")# pragma GCC target("avx,avx2,fma")#endif#include <bits/stdc++.h>using namespace std;#ifdef LOCAL# define LOG clog#elsestruct nullstream : ostream { nullstream() : ostream(nullptr) {}};nullstream LOG;#endif//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--//--#define FAST_IO \ ios::sync_with_stdio(false); \ cin.tie(nullptr);#define END return 0;using LL = long long;using ULL = unsigned long long;[[maybe_unused]]constexpr int _MAX = 1'234'567'891;[[maybe_unused]]constexpr int _MIN = -_MAX;[[maybe_unused]]constexpr LL __MAX = 1'111'111'111'111'111'111LL;[[maybe_unused]]constexpr LL __MIN = -__MAX;//--------------------------------------------------------------------------------------------------// solutionstruct EdmondsKarp { struct Edge { int to, rev, cap; }; int n; vector<vector<Edge>> g; EdmondsKarp(int n = 0) : n(n), g(n) {} void addEdge(int v, int u, int c) { Edge a { u, (int)g[u].size(), c }; Edge b { v, (int)g[v].size(), 0 }; g[v].push_back(a); g[u].push_back(b); } bool bfs(int s, int t, vector<int>& parentVertex, vector<int>& parentEdge) { fill(parentVertex.begin(), parentVertex.end(), -1); fill(parentEdge.begin(), parentEdge.end(), -1); queue<int> q; parentVertex[s] = s; q.push(s); while (!q.empty()) { int v = q.front(); q.pop(); for (int i = 0; i < (int)g[v].size(); ++i) { Edge& e = g[v][i]; if (e.cap <= 0 || parentVertex[e.to] != -1) { continue; } parentVertex[e.to] = v; parentEdge[e.to] = i; if (e.to == t) { return true; } q.push(e.to); } } return false; } int maxflow(int s, int t) { int flow = 0; vector<int> parentVertex(n); vector<int> parentEdge(n); while (bfs(s, t, parentVertex, parentEdge)) { int amount = INT_MAX; for (int cur = t; cur != s; cur = parentVertex[cur]) { int prev = parentVertex[cur]; int idx = parentEdge[cur]; amount = min(amount, g[prev][idx].cap); } for (int cur = t; cur != s; cur = parentVertex[cur]) { int prev = parentVertex[cur]; int idx = parentEdge[cur]; Edge& e = g[prev][idx]; e.cap -= amount; g[e.to][e.rev].cap += amount; } flow += amount; } return flow; }};/* 1. 이 문제를 푸는 한줄 핵심- 각 단방향 도로를 용량 1로 둔 최대 유량으로 1번 도시에서 2번 도시까지 서로 간선을 공유하지 않는 경로 수를 센다.*//* 2. 단계별 접근 과정 요약 (5줄 이내)- 입력 도로마다 같은 방향 용량 1 간선을 추가해 한 도로가 한 번만 쓰이게 한다.- 소스는 1번, 싱크는 2번 도시로 둔다.- Edmonds-Karp는 BFS로 최단 증가 경로를 하나씩 찾는다.- 증가 경로를 찾을 때마다 병목 용량만큼 유량을 흘린다.- 더 이상 증가 경로가 없으면 최대 유량 값을 출력한다.*/int main() { FAST_IO; int N, P; cin >> N >> P; EdmondsKarp ek(N + 1); for (int i = 0, a, b; i < P; ++i) { cin >> a >> b; ek.addEdge(a, b, 1); } cout << ek.maxflow(1, 2) << '\n'; END;}