zoukankan      html  css  js  c++  java
  • 二分图总结

    二分图总结

    匈牙利算法

    基于贪心的思想。

    • 首先从任意一个未配对的点 (x) 开始,选择他的任意一条边((x) - (y) ),如此时 (y) 还未配对,则配对成功,配对数加一,若 (y) 已经配对,则尝试寻找 的配对的另一个配对(该步骤可能会被递归的被执行多次),若该尝试成功,则配对成功,配对数加一。

    • 若果上一步配对不成功,那么选择重新选择一条未被选择过的边,重复上一步。

    • 对剩下每一个没有被配对的点执行步骤 1,直到所有的点都尝试完毕。

    最小点覆盖

    让每条边都至少和其中一个点关联。

    二分图最小点覆盖集的大小=二分图最大匹配集的大小

    最大独立集问题

    最多点,互不相连

    二分图最大独立集=图的点数-二分图最大匹配

    DAG图的最小路径覆盖

    解决此类问题可以建立一个二分图模型。把所有顶点 $i $拆成两个:X结点集中的 (i) 和Y结点集中的 (i') ,如果有边$i to j (,则在二分图中引入边)i to j'$,设二分图最大匹配为 (m) ,则结果就是$ n-m$

    最小路径覆盖数=原有向图节点数-新二分图最大匹配数。

    总结

    通过以上定理,只要通过匈牙利或者网络流就可以求出最大匹配,然后直接计算答案。一般考点在于对题目的分析,学会如何建图,这样才能做出题。

    KM算法

    一些申明

    • 顶标: 对于每个点有个值,要求 (forall i,j,A_{i}+B_{j} ge w(i,j))(w(i,j)),为边权,无边时为 $-propto $ 。
    • 交错树:每次dfs访问的点所形成的的一颗树
    • 相等子图:如果对于子图所有节点 和 满足 (A_{i}+B_{j} = w(i,j)) 的边 ,那么这个子图为相等子图。

    定理

    若相等子图中存在完备匹配,则这个完备匹配为这个二分图的带权最大匹配

    计算

    为了保证顶标符合条件,在所有 (i in T,j otin T) 的边 ((i,j)) ,找出最小的(A_{i}+B_{j}-w(i,j)) 作为(Delta) ,在原图中寻找完备匹配即可。不断重复上述条件,直到每个左边点匹配成功

    代码

    // 二分图带权最大匹配:KM算法
    const int N = 105;
    int w[N][N]; // 边权
    int la[N], lb[N]; // 左、右部点的顶标
    bool va[N], vb[N]; // 访问标记:是否在交错树中
    int match[N]; // 右部点匹配了哪一个左部点
    int n, delta, upd[N];
    
    bool dfs(int x) {
    	va[x] = 1; // 访问标记:x在交错树中
    	for (int y = 1; y <= n; y++)
    		if (!vb[y])
    			if (la[x] + lb[y] - w[x][y] == 0) { // 相等子图
    				vb[y] = 1; // 访问标记:y在交错树中
    				if (!match[y] || dfs(match[y])) {
    					match[y] = x;
    					return true;
    				}
    			}
    			else upd[y] = min(upd[y], la[x] + lb[y] - w[x][y]);
    	return false;
    }
    
    int KM() {
    	for (int i = 1; i <= n; i++) {
    		la[i] = -(1 << 30); // -inf
    		lb[i] = 0;
    		for (int j = 1; j <= n; j++)
    			la[i] = max(la[i], w[i][j]);
    	}
    	for (int i = 1; i <= n; i++)
    		while (true) { // 直到左部点找到匹配
    			memset(va, 0, sizeof(va));
    			memset(vb, 0, sizeof(vb));
    			delta = 1 << 30; // inf
    			for (int j = 1; j <= n; j++) upd[j] = 1 << 30; 
    			if (dfs(i)) break;
    			for (int j = 1; j <= n; j++)
    				if (!vb[j]) delta = min(delta, upd[j]);
    			for (int j = 1; j <= n; j++) { // 修改顶标
    				if (va[j]) la[j] -= delta;
    				if (vb[j]) lb[j] += delta;
    			}
    		}
    	int ans = 0;
    	for (int i = 1; i <= n; i++)
    		ans += w[match[i]][i];
    	return ans;
    }
    

    大致模型

    • 一分为二一个点拆开两边各一个
    • 行列模型
    • 黑白染色模型
    • 稳定婚姻模型
    • 最小点覆盖
    • 最大独立集
    • 最小路径覆盖
  • 相关阅读:
    新浪微博千万级规模高性能、高并发的网络架构经验分享
    PHP- 如何在终端输出带颜色的字体?
    淘宝大秒杀系统是如何设计的?
    如何打造千万级Feed流系统
    Redis实现分布式锁 php
    Ubuntu16.04 安装PHP7 的 imagick 扩展
    nginx配置http访问自动跳转到https
    使用Redis来实现LBS的应用
    PHP多进程编程初步
    选redis还是memcache,源码怎么说
  • 原文地址:https://www.cnblogs.com/ztz-cpp/p/12687451.html
Copyright © 2011-2022 走看看