目录
一、DFS
1.排列数字
842. 排列数字 - AcWing题库https://www.acwing.com/problem/content/844/
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define sync ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int N = 3e5 + 5;
int path[N];
bool state[N];
int n;
void dfs(int u){
// 输出方案
if(u > n){
for(int i = 1; i <= n; i ++) cout << path[i] << ' ';
cout << '\n';
}
for(int i = 1; i <= n; i ++){
// 数字i未被使用
if(!state[i]){
path[u] = i;
state[i] = true;
dfs(u + 1);
// 回溯 取出i
state[i] = false;
}
}
}
void solve(){
cin >> n;
dfs(1);
}
signed main(){
sync;
solve();
}
2.n-皇后问题
843. n-皇后问题 - AcWing题库https://www.acwing.com/problem/content/845/
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define sync ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int N = 3e2 + 5;
char res[N][N];
// 列,对角线,反对角线状态
bool c[N], d[N], ud[N];
int n;
void dfs(int r){
// 最后一行 输出答案
if(r == n){
for(int i = 0; i < n; i ++){
for(int j = 0; j < n; j ++){
cout << res[i][j];
}
cout << '\n';
}
cout << '\n';
}
//第r行
for(int i = 0; i < n; i ++){
if(!c[i] && !d[i + r] && !ud[n - i + r]){
res[r][i] = 'Q';
c[i] = d[i + r] = ud[n - i + r] = true;
dfs(r + 1);
//回溯
c[i] = d[i + r] = ud[n - i + r] = false;
res[r][i] = '.';
}
}
}
void solve(){
cin >> n;
for(int i = 0; i < n; i ++){
for(int j = 0; j < n; j ++){
res[i][j] = '.';
}
}
dfs(0);
}
signed main(){
sync;
solve();
}
二、BFS
1.走迷宫
844. 走迷宫 - AcWing题库https://www.acwing.com/problem/content/846/
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define sync ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
typedef pair <int, int> PII;
const int N = 110;
int ma[N][N]; // 地图
int d[N][N]; // 距离
int n, m;
void bfs(int a, int b){
queue <PII> q;
q.push({a, b});
while(!q.empty()){
PII start = q.front();
q.pop();
ma[start.first][start.second] = 1;
// 四个方向的偏移量
int dx[4] = {0, 1, 0, -1};
int dy[4] = {-1, 0, 1, 0};
// 往四个方向走
for(int i = 0; i < 4; i ++){
int x = start.first + dx[i];
int y = start.second + dy[i];
// 走没走过的地方
if(x > 0 && x <= n && y > 0 && y <= m && ma[x][y] == 0){
ma[x][y] = 1;
// 从当前点走过 距离+1
d[x][y] = d[start.first][start.second] + 1;
q.push({x, y});
}
}
}
cout << d[n][m];
}
void solve(){
cin >> n >> m;
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= m; j ++){
cin >> ma[i][j];
}
}
bfs(1, 1);
}
signed main(){
sync;
solve();
}
2.八数码
845. 八数码 - AcWing题库https://www.acwing.com/problem/content/847/
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define sync ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
typedef pair <int, int> PII;
const int N = 3e5 + 5;
int dx[] = {-1, 0, 1, 0};
int dy[] = {0, 1, 0, -1};
void bfs(string s){
string end = "12345678x"; // 目标状态
queue <string> q; // 队列q存储状态
unordered_map <string, int> d; // d存储状态与距离的关系
q.push(s); // 初始状态
d[s] = 0;
while(q.size()){
string t = q.front();
q.pop();
int dist = d[t];
if(t == end){
cout << dist << '\n';
return;
}
else{
// 状态转移
int k = t.find('x');
// 图和字符串的关系
int x = k/3;
int y = k%3;
for(int i = 0; i < 4; i ++){
int a = x + dx[i];
int b = y + dy[i];
if(a >= 0 && a < 3 && b >= 0 && b < 3){
swap(t[k], t[a*3 + b]);
// 更新距离
if(d.count(t) == 0){
d[t] = dist + 1;
q.push(t);
}
// 状态回溯
swap(t[k], t[a*3 + b]);
}
}
}
}
cout << "-1\n";
}
void solve(){
string s;
// 将3*3的图转化成字符串处理
for(int i = 0; i < 9; i ++){
string x;
cin >> x;
s += x;
}
bfs(s);
}
signed main(){
sync;
solve();
}
二、树与图的深度优先遍历DFS
树的重心
846. 树的重心 - AcWing题库https://www.acwing.com/problem/content/848/
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 5;
const int M = N * 2; // 以有向图形式存储无向图 每个节点最多2N-2条边
int h[N], e[M], ne[M], idx; // 邻接表存图
int n, res = INF;
bool st[N]; // 记录节点访问状态
// 以a为根 插入b
void add(int a, int b){
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
// 求以u为根的子树节点数
int dfs(int u){
st[u] = 1;
int cnt = 0; // cnt记录以u为重心的子树节点最大值
int sum = 1; // sum记录以u为重心的子树节点数 初始含u为1
for(int i = h[u]; i != -1; i = ne[i]){
int j = e[i];
if(!st[j]){
int size = dfs(j); // 以u为根的子树节点数
cnt = max(cnt, size);
sum += size;
}
}
// n-num则为整颗树减去以u为根的子树剩下的节点数
cnt = max(cnt, n - sum);
res = min(res, cnt);
return sum;
}
int solve(){
memset(h, -1, sizeof h);
cin >> n;
for(int i = 0; i < n - 1; i ++){
int a, b;
cin >> a >> b;
add(a, b);
add(b, a);
}
dfs(1);
return res;
}
signed main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while(t --){
// solve();
cout << solve() << '\n';
}
}
三、树与图的广度优先遍历BFS
图中点的层次
847. 图中点的层次 - AcWing题库https://www.acwing.com/problem/content/849/
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 5;
int e[N], h[N], ne[N], idx; // 邻接表存有向图
int dist[N];
int n, m;
void add(int a, int b){
e[idx] = b; ne[idx] = h[a], h[a] = idx ++;
}
int bfs(){
memset(dist, -1, sizeof dist); // 初始化距离
queue <int> q;
q.push(1);
dist[1] = 0; //到自己的距离为0
while(q.size()){
int t = q.front();
q.pop();
for(int i = h[t]; i != -1; i = ne[i]){
int j = e[i];
if(dist[j] == -1){
dist[j] = dist[t] + 1; // 更新距离
q.push(j);
}
}
}
return dist[n];
}
int solve(){
memset(h, -1, sizeof h);
cin >> n >> m;
while(m --){
int a, b;
cin >> a >> b;
add(a, b);
}
return bfs();
}
signed main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while(t --){
// solve();
cout << solve() << '\n';
}
}
四、拓扑排序
有向图的拓扑序列
848. 有向图的拓扑序列 - AcWing题库https://www.acwing.com/problem/content/850/
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 5;
int e[N], h[N], ne[N], idx;
int n ,m;
int d[N]; //存储各点的入度值
int res[N];
void add(int a, int b){
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
void topsort(){
queue <int> q;
idx = 0;
for(int i = 1; i <= n; i ++){
if(d[i] == 0){
q.push(i);
res[idx ++] = i;
}
}
while(q.size()){
int t = q.front();
q.pop();
for(int i = h[t]; i != -1; i = ne[i]){ //遍历入度为0的点指向的点
int j = e[i];
d[j] --; // 删除t指向j的边 j的入度减1
if(d[j] == 0){
q.push(j);
res[idx ++] = j;
}
}
}
if(idx == n){ // n个点都满足则该有向图为拓扑序列
for(int i = 0; i < idx; i ++) cout << res[i] << ' ';
}
else cout << -1;
}
void solve(){
memset(h, -1, sizeof h);
cin >> n >> m;
while(m --){
int a, b;
cin >> a >> b;
add(a, b);
d[b] ++;
}
topsort();
}
signed main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while(t --){
solve();
// cout << solve() << '\n';
}
}
五、Dijkstra
1.Dijkstra求最短路I(朴素)
849. Dijkstra求最短路 I - AcWing题库https://www.acwing.com/problem/content/851/
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int INF = 0x3f3f3f3f;
const int N = 5e2 + 5;
int n, m; // 节点数 边数
int g[N][N]; // 邻接矩阵存图
int dist[N]; // 存储距离
bool state[N]; // 存储更新状态
int dijkstra(){
memset(dist, 0x3f, sizeof dist); // 初始化距离为无穷大
dist[1] = 0; // 1号点到本身距离为0
// 循环n次 找到路径最短的点
for(int i = 0; i < n; i ++){
// 找未更新的、距离1号点最近的点
int t = -1;
for(int j = 1; j <= n; j ++){
if(!state[j] && (t == -1 || dist[t] > dist[j])) t = j;
}
state[t] = 1;
// 更新找到的点相邻点的距离
for(int j = 1; j <= n; j ++){
dist[j] = min(dist[j], dist[t] + g[t][j]);
}
}
if(dist[n] == 0x3f3f3f3f) return -1;
return dist[n];
}
int solve(){
cin >> n >> m;
memset(g, 0x3f, sizeof g);
while(m --){
int a, b, x;
cin >> a >> b >> x;
g[a][b] = min(g[a][b], x);
}
return dijkstra();
}
signed main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while(t --){
// solve();
cout << solve() << '\n';
}
}
2.Dijkstra求最短路II(堆优化)
850. Dijkstra求最短路 II - AcWing题库https://www.acwing.com/problem/content/852/
#include <bits/stdc++.h>
using namespace std;
//#define int long long // 开long long会出错
#define fi first
#define se second
typedef pair<int, int> PII;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 5;
int n, m; // 节点数 边数
int h[N], w[N], e[N], ne[N], idx; //邻接表建图
int dist[N]; // 距离
bool state[N]; // 状态
void add(int a, int b, int x){
e[idx] = b, w[idx] = x, ne[idx] = h[a], h[a] = idx ++;
}
int dijkstra(){
memset(dist, 0x3f, sizeof dist); // 距离初始化为无穷大
dist[1] = 0; // 到本身的距离为0
priority_queue <PII, vector <PII>, greater <PII>> heap; // 小根堆优化找dist最小值 pair <dist, 节点编号>
heap.push({0, 1});
while(heap.size()){
PII t = heap.top();
heap.pop();
int k = t.se, d = t.fi;
if(state[k]) continue; // 到当前节点距离已确定
state[k] = 1;
for(int i = h[k]; i != -1; i = ne[i]){
int j = e[i];
int di = d + w[i];
if(di < dist[j]){ // 更新最短距离
dist[j] = di;
heap.push({di, j});
}
}
}
if(dist[n] == INF) return -1;
return dist[n];
}
int solve(){
cin >> n >> m;
memset(h, -1, sizeof h);
while(m --){
int a, b, x;
cin >> a >> b >> x;
add(a, b, x);
}
return dijkstra();
}
signed main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while(t --){
// solve();
cout << solve() << '\n';
}
}
六、bellman-ford
有边数限制的最短路
853. 有边数限制的最短路 - AcWing题库https://www.acwing.com/problem/content/855/
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int INF = 0x3f3f3f3f;
const int N = 5e2 + 5;
const int M = 2e5 + 5;
struct edge{
int a, b, w;
}e[M];
int dist[N], back[N];
int n, m, k;
/*
*Bellman-ford算法是求含负权图的单源最短路径的一种算法,效率较低,代码难度较小。
*其原理为连续进行松弛,在每次松弛时把每条边都更新一下,若在 n-1 次松弛后还能更新,
*则说明图中有负环,因此无法得出结果,否则就完成。
*通俗的来讲就是:假设1号点到n号点是可达的,每一个点同时向指向的方向出发,更新相
*邻的点的最短距离,通过循环n-1次操作,若图中不存在负环,则1号点一定会到达 n 号点,
*若图中存在负环,则在 n-1 次松弛后一定还会更新。
*/
bool bellman_ford(){
memset(dist, INF, sizeof dist);
dist[1] = 0;
while(k --){
memcpy(back, dist, sizeof dist); // 备份数组防止串联情况
for(int i = 0; i < m; i ++){
int a = e[i].a, b = e[i].b, w = e[i].w;
dist[b] = min(dist[b], back[a] + w); // 松弛每个点到起点距离
}
}
if(dist[n] > INF / 2) return 0;
return 1;
}
void solve(){
cin >> n >> m >> k;
for(int i = 0; i < m; i ++){
int a, b, w;
cin >> a >> b >> w;
e[i] = {a, b, w};
}
if(bellman_ford()) cout << dist[n] << '\n';
else cout << "impossible\n";
}
signed main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while(t --){
solve();
// cout << solve() << '\n';
}
}
七、spfa
1.spfa求最短路
851. spfa求最短路 - AcWing题库https://www.acwing.com/problem/content/853/
#include <bits/stdc++.h>
using namespace std;
// #define int long long // 开long long会出错
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 5;
int h[N], e[N], w[N], ne[N], idx;
int dist[N];
bool state[N];
int n, m;
void add(int a, int b, int x){
e[idx] = b; w[idx] = x; ne[idx] = h[a]; h[a] = idx ++;
}
bool spfa(){
memset(dist, INF, sizeof dist);
dist[1] = 0;
queue <pair <int, int>> q; // 记录当前发生过更新的点 state[]可逆
q.push({0, 1});
state[1] = 1;
while(q.size()){ // spfa仅适用无负权回路
pair <int, int> t = q.front();
q.pop();
int k = t.second;
state[k] = 0; //标记为false 如果发生更新则可以入队
for(int i = h[k]; i != -1; i = ne[i]){
int j = e[i];
int di = dist[k] + w[i];
if(di < dist[j]){ // 更新最短距离
dist[j] = di;
if(!state[j]){
state[j] = 1;
q.push({dist[j], j});
}
}
}
}
if(dist[n] == INF) return 0;
return 1;
}
void solve(){
memset(h, -1, sizeof h);
cin >> n >> m;
while(m --){
int a, b, x;
cin >> a >> b >> x;
add(a, b, x);
}
if(spfa()) cout << dist[n] << '\n';
else cout << "impossible\n";
}
signed main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while(t --){
solve();
// cout << solve() << '\n';
}
}
2.spfa判断负环
852. spfa判断负环 - AcWing题库https://www.acwing.com/problem/content/854/
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 5;
int h[N], e[N], w[N], ne[N], idx;
int dist[N], cnt[N]; // cnt[x] 表示当前从1~x的最短路的边数
bool state[N];
int n, m;
void add(int a, int b, int x){
e[idx] = b; w[idx] = x; ne[idx] = h[a]; h[a] = idx ++;
}
/*
*求负环一般使用SPFA算法 方法是用一个cnt数组记录每个点到源点的边数
*一个点被更新一次就+1 一旦有点的边数达到了n那就证明存在了负环
*/
bool spfa(){
// memset(dist, INF, sizeof dist); // 无需初始化 因若存在负环 无论dist初始值都会被更新
queue <int> q; // 所有点都有可能有负环 均入队
for(int i = 1; i <= n; i ++){
q.push(i);
state[i] = 1;
}
while(q.size()){
auto t = q.front();
q.pop();
state[t] = 0;
for(int i = h[t]; i != -1; i = ne[i]){
int j = e[i];
int di = dist[t] + w[i];
if(di < dist[j]){
dist[j] = di;
cnt[j] = cnt[t] + 1;
if(cnt[j] >= n) return 1; // 经过超过n-1条边 存在负环
if(!state[j]){
state[j] = 1;
q.push(j);
}
}
}
}
return 0;
}
void solve(){
memset(h, -1, sizeof h);
cin >> n >> m;
while(m --){
int a, b, x;
cin >> a >> b >> x;
add(a, b, x);
}
if(spfa()) cout << "Yes\n";
else cout << "No\n";
}
signed main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while(t --){
solve();
// cout << solve() << '\n';
}
}
八、Floyd
Floyd求最短路(多源汇最短路问题)
854. Floyd求最短路 - AcWing题库https://www.acwing.com/problem/content/856/
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int INF = 0x3f3f3f3f;
const int N = 2e2 + 5;
int n, m, k;
int d[N][N];
/*
*状态表示:f[k][i][j]表示经过前k个点从i到j的距离
*状态转换:f[k-1][i][j]表示不经过k从i到j
* f[k - 1][i][k] + f[k - 1][k][j]表示经过k从i到j
*状态转移方程:d[i][j] = min(d[i][j],d[i][k] + d[k][j])
*/
void floyd(){
for(int k = 1; k <= n; k ++){
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= n; j ++){
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
}
}
}
int solve(){
cin >> n >> m >> k;
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= n; j ++){
if(i == j) d[i][j] = 0;
else d[i][j] = INF;
}
}
while(m --){
int a, b, x;
cin >> a >> b >> x;
d[a][b] = min(d[a][b], x);
}
floyd();
while(k --){
int x, y;
cin >> x >> y;
if(d[x][y] > INF / 2) cout << "impossible\n";
else cout << d[x][y] << '\n';
}
}
signed main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while(t --){
// solve();
cout << solve() << '\n';
}
}
九、Prim
Prim算法求最小生成树
#include <bits/stdc++.h>
using namespace std;
// #define int long long
const int INF = 0x3f3f3f3f;
const int N = 5e2 + 5;
int g[N][N]; // 邻接表存稠密图
int d[N], p[N]; // d[]存各点到生成树的距离 p[]为各节点的前去节点
bool state[N]; // 存储节点是否被加入生成树的状态
int n, m;
void prim(){
memset(d, INF, sizeof d);
d[1] = 0;
int res = 0;
// 循环n次找出一个点加入生成树
for(int i = 0; i < n; i ++){
int t = -1;
for(int j = 1; j <= n; j ++){
// 选择不在树中且到树的距离最短的点
if(!state[j] && (t == -1 || d[j] < d[t])) t = j;
}
// 判断该点是否孤立
if(d[t] == INF){
cout << "impossible\n";
return;
}
state[t] = 1;
res += d[t];
// 更新生成树外的点到生成树的距离
for(int i = 1; i <= n; i ++){
if(!state[i] && d[i] > g[t][i]){
d[i] = g[t][i];
p[i] = t;
}
}
}
cout << res << '\n';
}
void getPath(){
// 共n-1条边
for(int i = n; i > 1; i --) cout << i << ' ' << p[i] << '\n';
}
void solve(){
memset(g, INF, sizeof g);
cin >> n >> m;
while(m --){
int a, b, x;
cin >> a >> b >> x;
g[a][b] = g[b][a] = min(g[a][b], x);
}
prim();
}
signed main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while(t --){
solve();
// cout << solve() << '\n';
}
}
十、Kruskal
Kruskal算法求最小生成树
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 5;
int p[N];
int n, m;
int res, cnt; // res记录生成树的树边权重之和 cnt记录全部加入到树的(多个)集合中边的数量
struct edge{
int a, b, w;
}e[N];
// 按边的权重升序排序
bool cmp(edge a, edge b){
return a.w < b.w;
}
int find(int x){
return x == p[x] ? x : (p[x] = find(p[x]));
}
void kruskal(){
for(int i = 0; i < m; i ++){
int a = e[i].a, b = e[i].b, w = e[i].w;
// a、b节点在不同集合才将a-b边加入生成树中
if(find(a) != find(b)){
p[find(a)] = p[find(b)];
cnt ++;
res += w;
}
}
if(cnt == n - 1) cout << res << '\n'; // n-1条边可以生成n个节点的树
else cout << "impossible\n";
}
void solve(){
cin >> n >> m;
for(int i = 0; i < n; i ++) p[i] = i;
for(int i = 0; i < m; i ++){
int a, b, w;
cin >> a >> b >> w;
e[i] = {a, b, w};
}
sort(e, e + m, cmp);
kruskal();
}
signed main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while(t --){
solve();
// cout << solve() << '\n';
}
}
十一、染色法判定二分图
染色法判断二分图
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 5;
int h[N], e[N], ne[N], idx; // 邻接表存图
int color[N]; // 存储各点颜色状态 0 1 2分别表示未染色 红色 蓝色
int n, m;
void add(int a, int b){
e[idx] = b; ne[idx] = h[a]; h[a] = idx ++;
}
bool dfs(int u, int c){
color[u] = c; // 染色
for(int i = h[u]; i != -1; i = ne[i]){
int t = e[i];
if(!color[t]){ // 相邻的点未染色
if(!dfs(t, 3 - c)) return 0; //处理相邻点 2 <- 1, 1 <- 2
}
// 相邻点染色状态与u冲突
else if(color[t] && color[t] != 3 - c) return 0;
}
return 1;
}
void solve(){
memset(h, -1, sizeof h);
cin >> n >> m;
for(int i = 1; i <= m; i ++){
int a, b;
cin >> a >> b;
add(a, b); add(b, a);
}
for(int i = 1; i <= n; i ++){
if(!color[i]){
if(!dfs(i, 1)){
cout << "No\n";
return;
}
}
}
cout << "Yes\n";
}
signed main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while(t --){
solve();
// cout << solve() << '\n';
}
}
十二、匈牙利算法
二分图的最大匹配
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 5;
int h[N], e[N], ne[N], idx; // 邻接表存图
int n1, n2, m;
bool state[N]; // 匹配状态
int match[N]; // 表示相匹配的点
void add(int a, int b){
e[idx] = b; ne[idx] = h[a]; h[a] = idx ++;
}
int find(int x){
// 遍历能够匹配的点
for(int i = h[x]; i != -1; i = ne[i]){
int j = e[i];
if(!state[j]){ // 找到预计情况下未匹配的点相匹配
state[j] = 1;
if(!match[j] || find(match[j])){ // 该点确实未匹配则与之匹配
match[j] = x;
return 1;
}
}
}
return 0;
}
void solve(){
memset(h, -1, sizeof h);
cin >> n1 >> n2 >> m;
while(m --){
int a, b;
cin >> a >> b;
add(a, b);
}
int res = 0;
for(int i = 1; i <= n1; i ++){
// 每次模拟匹配的预定情况不一样 均需初始化
memset(state, 0, sizeof state);
if(find(i)) res ++;
}
cout << res << '\n';
}
signed main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while(t --){
solve();
// cout << solve() << '\n';
}
}