求二分图的算法――匈牙利
- 例题:
https://www.luogu.org/problem/P3386
- 思路:
首先二分图是一个求一堆东西(例如狗),喜欢一些东西(例如肉),但是他们喜欢的肉不同,求最大限度能满足多少条狗的问题。那么我们可以画一个图,把狗放在一侧,把肉放在一侧。 如果第i只狗, 喜欢第j个肉,那么,就从i-->j连一条有向边。 然后, 我们用贪心的思想进行dfs。 我们定义choose[i]表示第i个肉被第choose[i]个狗获得。 然后我们定义一个vis数组,防止死循环。 我们枚举1 ~ n,dfs判断第i只狗能否吃到肉。 dfs中,我们枚举i所喜欢的肉,如果第j个肉没有被吃 || 吃这个肉的狗可以吃别的肉,那么就return 1(及当前狗可以吃到肉),否则return 0。 如果return 1,就ans++(及可以吃到自己喜欢的肉的狗的数量++)。 注意:每次dfs都要把vis清空。 最后答案就是ans。
- 代码:
1 #include <bits/stdc++.h> 2 #define INF 0x3f3f3f3f 3 using namespace std; 4 int n, m, edge, head[100001], vis[100001], choose[100001], num, ans; 5 struct node 6 { 7 int next, to; 8 }stu[10000001]; 9 inline void add(int x, int y)//存图 10 { 11 stu[++num].next = head[x]; 12 stu[num].to = y; 13 head[x] = num; 14 return; 15 } 16 inline int dfs(int u)//贪心dfs 17 { 18 for(register int i = head[u]; i; i = stu[i].next)//枚举当前点所喜欢的东西 19 { 20 int k = stu[i].to; 21 if(vis[k]) 22 { 23 continue; 24 } 25 vis[k] = 1; 26 if(!choose[k] || dfs(choose[k]))//如果没人要或者要这个东西的人可以要别的东西 27 { 28 choose[k] = u;//这个东西的物主变成u了 29 return 1; 30 } 31 } 32 return 0; 33 } 34 signed main() 35 { 36 scanf("%d %d %d", &n, &m, &edge); 37 for(register int i = 1, x, y; i <= edge; ++i) 38 { 39 scanf("%d %d", &x, &y); 40 if(x > n || y > m)//特判一下 41 { 42 continue; 43 } 44 add(x, y);//建边 45 } 46 for(register int i = 1; i <= n; ++i) 47 { 48 memset(vis, 0, sizeof(vis));//清空 49 ans += dfs(i);//直接+就好了 50 } 51 printf("%d", ans); 52 return 0; 53 }
来源:博客园
作者:louis_110
链接:https://www.cnblogs.com/qqq1112/p/11620774.html