P3386 【模板】二分图最大匹配 题解(匈牙利算法)

题目连接

题目思路

如果不要去证明这个算法的正确性的话,我认为这只能算是一个简单贪心的dfs

可能一直被它高深的名字骗了没有去深入学习

时间复杂度\(O(nm)\) \(n\)代表点数,\(m\)代表边数

算法流程大概是如下 参考洛谷的题解

1.从任意一个没有被配对的点x开始,从点x的边中任意选一条边。如果此时点i没有被配对那么配对成功,则找到了一条增广路。如果点i此时已经被配对了,那么可以尝试将点match[i]与其他点配对。如果尝试成功,则找到一条增广路。这里用match[ ]来记录配对关系, 即match[i] = x。 并且将配对数+1。 这个过程我们用dfs来实现。

2.如果配对失败,就从点x的边中重选一条边尝试。直到点x配对成功或尝试完x所有的边。

3.接下来对没有配对的点一一进行配对,直到所有的点都尝试完毕找不到新的增广路。

二分图染色好像能解决一堆覆盖问题,以后有机会再好好了解下吧

代码

#include<bits/stdc++.h>
#define fi first
#define se second
#define debug cout<<"I AM HERE"<<endl;
using namespace std;
typedef long long ll;
const int maxn=5e2+5,inf=0x3f3f3f3f,mod=1e9+7;
const double eps=1e-6;
int n,m,e;
vector<int> g[maxn];
bool vis[maxn];
int match[maxn];
bool dfs(int u){
    for(auto x:g[u]){
        if(vis[x]) continue;
        vis[x]=1;
        if(match[x]==-1||dfs(match[x])){
            match[x]=u;
            return 1;
        }
    }
    return 0;
}
signed main(){
   scanf("%d%d%d",&n,&m,&e);
   for(int i=1,u,v;i<=e;i++){
        scanf("%d%d",&u,&v);
        g[u].push_back(v);
   }
   int ans=0;
   memset(match,-1,sizeof match);
   for(int i=1;i<=n;i++){
        memset(vis,0,sizeof vis);
        ans+=dfs(i);
   }
   printf("%d\n",ans);
    return 0;
}

posted @ 2022-03-01 15:28  hunxuewangzi  阅读(34)  评论(0编辑  收藏  举报