匈牙利算法

1.最大匹配&完美匹配
在图论中,一个“匹配”(matching)是一个边的集合,其中任意两条边都没有公共顶点。
最大匹配:一个图所有匹配中,所含匹配边数最多的匹配,称为这个图的最大匹配。
完美匹配:如果一个图的某个匹配中,所有的顶点都是匹配点,那么它就是一个完美匹配。
2.交替路&增广路
交替路:从一个未匹配点出发,依次经过非匹配边、匹配边、非匹配边…形成的路径叫交替路。
增广路:从一个未匹配点出发,走交替路,如果途径另一个未匹配点(出发的点不算),则这条交替路称为增广路。
增广路的重要特点:非匹配边比匹配边多一条,因此,研究增广路的意义是改进匹配。只要把增广路中的匹配边和非匹配边的身份交换即可。由于中间的匹配节点不存在其他相连的匹配边,所以这样做不会破话匹配的性质。交换后,图中的匹配边数目+1。
我们可以通过不停地寻找增广路来增加匹配中的匹配边和匹配点,找不到增广路时,达到最大匹配。

二分图的最小顶点覆盖:在二分图中求最少的边,让每条边至少和其中的一个点关联
最小顶点覆盖=最大匹配数
DAG图(无回路有向图)的最小路径覆盖:用尽量少的不相交的简单路径覆盖图中的所有顶点
最小路径覆盖=顶点数-最大匹配数
无向图的最小路径覆盖=顶点数-最大二分匹配/2(因为无向图就是双向的一条边等于两次入图正向和反向)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 1000 + 4;
int map[maxn][maxn];
int link[maxn], vis[maxn];
int n, m, e, ans;
bool dfs(int u) {
    for(int v = 1; v <= m; ++v) {
        if(!vis[v] && map[u][v]) {
            vis[v] = 1;
            if(!link[v] || dfs(link[v])) {
                link[v] = u;
                return true;
            }
        }
    }
    return false;
}
void xyl() {
    memset(link, 0, sizeof(link));
    for(int i = 1; i <= n; ++i) {
        memset(vis, 0, sizeof(vis));
        if(dfs(i)) ans++;
    }
}
int main()
{
    cin >> n >> m >> e;
    int u, v;
    for (int i = 0; i < e; ++i) {
        cin >> u >> v;
        map[u][v] = 1;
    }
    xyl();
    cout << ans << endl;
}

你可能感兴趣的:(总结)