二分图

二分图:把一个图的顶点划分为两个不相交子集 ,使得每一条边都分别连接两个集合中的顶点。也就是每个集合的点只能有向另一个集合的边。

一定不含有奇数环,计数环的话一定有一个是自己连向自己的集合

可能是偶数环,不一定是联通图

染色法

  • 相邻的点染不同的颜色,用1,2表示两种颜色,0表示未染色

  • 遍历一下,没染色的就进行dfs染色

  • 只有当某个点染色失败才表示染色失败,当所有的点都不失败的时候,就是染色成功

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <set>
    #include <queue>
    #include <vector>
    #include <map>
    #include <unordered_map>
    #include <cmath> 
    #include <stack>
    #include <iomanip>
    #include <deque> 
    #include <sstream>
    #define x first
    #define y second
    using namespace std;
    typedef long double ld;
    typedef long long LL;
    typedef pair<int, int> PII;
    typedef pair<double, double> PDD;
    typedef unsigned long long ULL;
    const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
    const double eps = 1e-8;
    int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
    int h[N], e[M], ne[M], w[M], idx;
    void add(int a, int b, int v = 0) {
        e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
    }
    int n, m, k;
    int a[N];
    int st[N];
    bool dfs(int u, int co) {
        st[u] = co;
        for (int i = h[u]; ~i; i = ne[i]) {
            int j = e[i];
            if (!st[j]) {
                if (!dfs(j, 3 - co)) return false;
            }
            else  if (st[j] == st[u]) return false;
        }
        return true;
    }
    // 递归搜索栈,当前状态由后续决定,先将当前状态暂定,然后搜后续状态再由后续状态回溯
    int main() {
        ios::sync_with_stdio(false), cin.tie(0);
        memset(h, -1, sizeof h);
        cin >> n >> m;
        while (m --) {
            int a, b;
            cin >> a >> b;
            add(a, b), add(b, a);
        }
        bool ok = true;
        for (int i = 1; i <= n; i ++ ) 
            if (!st[i]) {
                if (!dfs(i, 1)) {
                    ok = false;
                    break;
                }
            }
        if (ok) cout << "Yes" << endl;
        else cout << "No" << endl;
        return 0;
    }
    

二分图最大匹配问题

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

二分图的最大匹配:所有匹配中包含边数最多的一组匹配被称为二分图的最大匹配,其边数即为最大匹配数。

任意两条边都没有公共顶点,直观感受就是,每次看这个男生喜欢的女生喜欢的男生是否可以喜欢别的女生,不可以的话就代表这个女生被那个男生锁死了,如果当前这个男生没有别的可以喜欢的了最多也就是一换一没有贡献所以这样是最优的,否则这个女生可以变心,那个男生还可以喜欢别的人。

最小点覆盖:选取最少的点,可以让每个边都至少包含一个被选的点。

匹配边:与其他边没有公共节点的一条边

匹配点:匹配边上的点

非匹配点:不在匹配边上的点

非匹配边:图中两点之间不是匹配边的边

最大匹配:最多连多少条边,使得所有的边无公共点

增广路径:一个非匹配点到另一个非匹配点的一条非匹配边和匹配边交替经过的路径**。->最大匹配中不存在增广路径,因为如果有增广路径,就可以让路径上所有的非匹配边和匹配边互换使得最大匹配数加一。

最小点覆盖问题

在二分图中最小点覆盖 == 最大匹配数,最后左边都是未标记的匹配边,右边都是标记的匹配边

则需证最小点覆盖A ≥ 最大匹配数B - 最大匹配m-最少要选m个点来覆盖m个边(匹配里两两没有交点)
最大匹配数B = 最小点覆盖A等号可以成立 - 构造一种方案 --由于最小点覆盖是所有方案的最小值

构造:
1 求最大匹配(匈牙利)
2 从左边每个非匹配点{a,b}出发 向右边做一遍增广(两条横虚线- -)
o o

ao - -.
/
/
o o

bo - -.
. —— o


o
3 标记所有经过的点 标记为。 而未被经过的点依然是o
。 o
\ -> e1
a。- -。3
/
/
。 o
\ -> e2
b。- -。2

  1. —— o -> e3


    oc
    左部所有未被标记的点{1}和右边所有被标记的点{2,3}
    1 左边所有非匹配点一定都被标记了(它们是出发点) / 左边未被标记的点一定是匹配点(1)
    2 右边所有非匹配点一定没被标记(否则就找到了增广路) / 右边所有被标记的点一定是匹配点(2,3)
    回顾增广路定义:从左边非匹配点->右边非匹配点的路径
    而被标记代表从左边非匹配点出发走到了右边的非匹配点
    3 对于匹配边 左右两个点要么同时被标记 要么同时不被标记(因为在寻找增广路的过程中,左部匹配点只能通过右部到达。)
    ⭐对每个匹配边必然只选一个点 - 选右边被标记的点{2,3}/选左边没被标记的点{1}
    此时:我们选的点(.)的数量==匹配数(e1、e2、e3)

0 首先定义当前满足假设:左边右边都在匹配边肯定是被最大匹配树中得匹配边覆盖的
不在匹配中的点所在的边是否被最大匹配数中的匹配边覆盖?
1 左边非匹配点i → 右边匹配点j (如边a-3,边b-2)
因为i是出发点,所以j一定被标记。而我们选了右部所有被标记的点(⭐处),因此这样的边也被覆盖。
2 左边匹配点i → 右边非匹配点j(如边1-c 右边非匹配点==未被标记的点)
i一定没有被标记,否则再走到j就找到了增广路。而我们选了左部所有未被标记的点(⭐处),因此这样的边也被覆盖。
画出i被标记的例子就可说明为什么
0。-- 。 ->被标记的点都是能从左边非匹配点0出发经过i后才标记i的
/ 如果能从i->j,则说明找到一条0-j的增广路,则可以多出一条匹配边
/ 与最大匹配矛盾
i。—— o


o j
3 左边右边都不匹配(此时可以在最大匹配加一条新的边) -- 这和当前这个匹配是最大匹配矛盾

因此 我们构造出的情况恰好选3个点且将最大3条匹配边覆盖住

最大独立集:在一个图中选出最多的点,使得选出的点之间没有边。

选出最多的点使得选出的点之间没有边,等价说选出最少的点把原图中所有的边破坏掉

也就是选出最少的点把原图中所有的点覆盖住,即最小点覆盖问题.

所以最大独立集就是,总点数减去最小点覆盖数

最大团:在一个图中选出最多的点,使得任意两点之间有边

最小路径覆盖:针对一个有向无环图(DAG),用最少条互不相交的路径,覆盖所有点.(其中互补相交是指点不重复)

最小路径覆盖 = 总点数 - 最大匹配

拆点:一个点分成两个点,分别表示出点和入点,那么从i->j的一条边就用,从左边点的出点i连到右边点的入点j'表示,于是得到的图就是一个二分图,所有的边就是左部和右部之间的,内部是没有点的.

转化:此时将原图中的每一条路径都转化为新图中,因为原图中的路径互不相交,所以每一个点最多只有一个入度和出度,意味着新图中,左部每一个点只会向右部连一条边,右部的点最多只会有一条边连入,每个点最多只会属于一条边

原图中的一条路径等价于新图中的一组匹配

原图中每一条路径的终点等价于新图中左部的非匹配点

求原图中互不相交的路径书,求路径的终点最少,左部的非匹配点最少,也就是最大匹配

最小路径重复点覆盖: 求一个传递闭包后就是最小路径覆盖

在该题中,记最小路径重复点覆盖数为cnt,该题的答案就是cnt
证明:
①k<=cnt
这cnt条路径覆盖了所有的点,所以所求的k个点一定要从这cnt条路径中的点选,
并且每条路径上最多选一个点,所以k<=cnt
②k>=cnt
构造:将cnt条路径的终点都放到一个集合E中,记next(E)返回的是从E中的每个点出发能到的所有点的集合
分类讨论:
i)E ∩ next(E) = Ø ,此时E内的点不能相互到达,说明E中所有的点就是一种k=cnt的方案
ii)E ∩ next(E) ≠ Ø , 对于E中的任何一个点p,让这个点反向走,直到这个点走到一个不在next(E-p)中的点,可证当这个点走到起点时肯定不在next(E-p)中。
反证法:如果这个点走到起点,仍在next(E-p)中,说明p所在的路径的起点可以被其他路径到达,那么这条路径就没有存在的意义可以省去,不满足最小路径重复点覆盖。
所以此时同样可以在每一条路径中选出一个点,使得这些点之间两两不可到达,即k=cnt

posted @ 2022-03-31 17:10  枉玊  阅读(155)  评论(0)    收藏  举报