#include using namespace std; const int N = 510; const int M = 100010; int n1, n2; //左边有n1个点,右边有n2个点 int m; //共有m条边 int h[N], e[M], ne[M], idx; //邻接表 int match[N]; //右边点对应的左边哪个点 bool st[N]; //是不是已经匹配过 int res; //记录结果数值,成功匹配的对数 //邻接表建图 void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx++; } /** * 功能:为每个男生找妹子 * @param x * @return */ bool find(int u) { //枚举每一个看上的集合 for (int i = h[u]; ~i; i = ne[i]) { int j = e[i]; if (!st[j]) { //本轮次匹配时,没有男生相中的女生(动态,临时概念) st[j] = true; //有人相中了 // match[j] == 0:如果j女生以前没有男朋友,那OK,可以 // find(match[j]):如果j的男朋友match[j]可以找其它女生 if (match[j] == 0 || find(match[j])) { //设置女生j的男朋友是u,逆袭成功! match[j] = u; return true; } } } return false; } int main() { //左边点数,右边点数,m条边 cin >> n1 >> n2 >> m; //初始化邻接表 memset(h, -1, sizeof h); //读入m条边建图 for (int i = 0; i < m; i++) { int a, b; cin >> a >> b; //存的是左边指向右边,因为在代码中只找左边进行梳理,不会去遍历右边,所以只存一边 //不必保存右边结点指向左边结点的边 add(a, b); } //枚举左侧的每个点 for (int i = 1; i <= n1; i++) { //表示后来的更牛,它看上的妹子,就会让其它人让出来,都是没有人选择过的状态! //就是本轮状态标识的作用,而不是全局状态标识 memset(st, false, sizeof st); //如果成功找到妹子,个数加1 if (find(i)) res++; } //输出结果 printf("%d\n", res); return 0; }