算法图论学习-二分图

169 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情

二分图

二分图简单来说就是将图中的所有点分成两个集合并且同一集合中的点之间没有连边,如果任意几个中一点与另一集合中的点都有连边,那我们称这个二分图为完全二分图 image.png
这就是一个简单的二分图

二分图的辨别方式

因为二分图是将图中的点分成两个集合所有我们采用染色法一个集合中染成红色另一个集合中全部染成绿色。如果发现染色有冲突那么这个图就不是一个二分图

const int N = 2e5 + 10;
vector<int> e[N];
bool flag = true; // flag表示是不是出现了冲突
bool st[N]; //防止重复染色
int f[N]; // 染色标记
void dfs(int x,int v) { // 用 0,1表示是因为1 ^ 1 = 0,0 ^ 1 = 1
    st[x] = true;
    f[x] = v;
    for(auto u : e[x]) {
        if(!st[u]) dfs(u,v ^ 1);
        if(f[u] == f[x]) flag = false;
    }
}

通过上述代码我们就可以去辨别这个图是不是一个二分图

匈牙利算法(解决二分图的最大匹配问题)

如果两个点集中的一点只能连接一次那么我们怎么才能知道二分图的最大连接数呢? 这时就有了匈牙利算法的出现,这个算法的原理很简单就是如果发现一个点a可以连接的一个点b已经连过点c了那我们看点c能不能挪个位置连到点d如果可以的话那么点a就可以连接到点b了

Code

bool find(int u) {
    b[u] ++;
    for(auto v : e[u]) {
        if(!f[v] || !b[f[v]] && find(f[v])) {
            f[v] = u;
            return true;
        }
    }
    return false;
}

int match(int n) {
    int res = 0;
    for(int i = 1; i <= n; i++) {
        memset(b, 0, sizeof(b));
        if(find(i)) res ++;
    }
    return res;
}