Loading

浅谈二分图

二分图匹配

给定一个二分图G,在G的一个子图M中,M的边集E中的任意两条边都不依附于同一个顶点,则称M是一个匹配。

二分图判定

如果一个图是连通的,可以用如下的方法判定是否是二分图:

在图中任选一顶点v,定义其距离标号为0,然后把它的邻接点的距离标号均设为1,接着把所有标号为1的邻接点均标号为2(如果该点未标号的话),如图所示,以此类推。

标号过程可以用一次BFS实现。标号后,所有标号为奇数的点归为X部,标号为偶数的点归为Y部。

接下来,二分图的判定就是依次检查每条边,看两个端点是否是一个在X部,一个在Y部。

如果一个图不连通,则在每个连通块中作判定。代码如下:

bool possibleBipartition(int n, vector<vector<int>>& dislikes) {
    vector<vector<int>> mp(n + 1);
    for(auto& dislike: dislikes) {
        mp[dislike[0]].push_back(dislike[1]);
        mp[dislike[1]].push_back(dislike[0]);
    }

    vector<int> vis(n + 1, -1);
    queue<int> que;
    for(int x = 1; x <= n; x++) {
        if(vis[x] != -1) {
            continue;
        }
        que.push(x);
        vis[x] = 0;
        while(!que.empty()) {
            int curr = que.front();
            que.pop();
            for(int i = 0; i < mp[curr].size(); i++) {
                int nxt = mp[curr][i];
                if(vis[nxt] == -1) {
                    vis[nxt] = (vis[curr] + 1) % 2;
                    que.push(nxt);
                } else if(vis[curr] == vis[nxt]){
                    return false;
                }
            }
        }
    }
    return true;
}

匈牙利算法

用增广路求最大匹配(称作匈牙利算法)

算法轮廓:

  1. 置M为空
  2. 找出一条增广路径P,通过取反操作获得更大的匹配M’代替M
  3. 重复2操作直到找不出增广路径为止

代码如下:

bool dfs(int a)
{
    for(int i=1;i<=n;i++)
    {
        if(mp[a][i]==1&&!visit[i])
        {
            visit[i]=1;
            if(link[i]==0||dfs(link[i]))
            {
                link[i]=a;
                return true;
            }
        }
    }
    return false;
}
void hungarian()
{  
    int ans=0; 
    for(int i=1;i<=m;i++) 
    { 
        memset(visit,0,sizeof(visit)); 
        if(dfs(i)) 
            ans++;
    }
}
posted @ 2018-07-28 08:56  天使的羽翼  阅读(255)  评论(0编辑  收藏  举报