图论二分图的应用(染色法判断二分图,最大匹配,最小点覆盖,最大独立集,最小路径点覆盖,最小路径重复点覆盖)

Posted a碟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图论二分图的应用(染色法判断二分图,最大匹配,最小点覆盖,最大独立集,最小路径点覆盖,最小路径重复点覆盖)相关的知识,希望对你有一定的参考价值。

目录

概念

什么是二分图?

顾名思义就是能分成两个部分的图
二分图是一个图,它的顶点可以分为两个独立的集合 U U U V V V,这样每一条边(u,v)(一个点在 U U U,一个点在 V V V)要么从 u u u v v v连接一个顶点,要么从 v v v u u u连接一个顶点。换句话说,对于每一条边(u,v),要么 u u u属于 U U U,要么 v v v属于 V V V,或者 u u u属于 V V V v v v属于 U U U,也可以说没有边连接同一集合的不同点

二分图的判定

二分图<=>不存在奇数环<=>染色法不存在矛盾

  • 只要染色法不存在矛盾,那么假定黑白染色,染色为黑色的放在一个集合,染色为白色的放在一个集合,这显然是一个二分图。
  • 所以可以用染色法来判定是否是二分图,如果可以通过两种颜色将图染色,使得相同集合中的顶点使用相同的颜色,则为二分图。无法使用两种颜色为奇数顶点个数的图染色。
    如下图所示,这是个奇数环,那么免不了有两个染色相同的点会相连

匹配问题

名词概念

  • 匹配: 设G=<V, E>为二分图,如果 M⊆E,并且 M 中两点没有任何两点有公共端点(被其他匹配的边共用),则成M为G的一个匹配。【也就是说匹配的实质是一些边的集合。】图三图四,就是图二的匹配

    我们定义匹配点、匹配边、未匹配点、非匹配边,它们的含义非常显然。例如图 3 中 1、4、5、7 为匹配点,其他顶点为未匹配点;1-5、4-7为匹配边,其他边为非匹配边。
  • 最大匹配: 边数最多的匹配,图四就是一个最大匹配
  • 最小点覆盖: 用尽可能少的点去覆盖所有的边【最小点覆盖集是点的集合,其个数为最小点覆盖数】
  • 最大独立集: 选出最多的点,使得选出的点之间没有边
  • 最大团: 选出最多的点,使得选出的点之间都有边
  • 最小路径点覆盖 :针对一个DAG(有向无环图),用最少的,互不相交的路径(点不重复),将所有点覆盖住。
  • 增广路径: 从一个非匹配点走,先走非匹配边,再走匹配边,再走非匹配边…最后走到一个非匹配点。图 5 中的一条增广路如图 6 所示(图中的匹配点均用红色标出)。最大匹配等价于不存在增广路径


    增广路有一个重要特点:非匹配边比匹配边多一条。只要把增广路中的匹配边和非匹配边的身份交换即可。由于中间的匹配节点不存在其他相连的匹配边,所以这样做不会破坏匹配的性质。交换后,图中的匹配边数目比原来多了 1 条。 我们可以通过不停地找增广路来增加匹配中的匹配边和匹配点。找不到增广路时,达到最大匹配(这是增广路定理)。匈牙利算法正是这么做的。

匈牙利算法

匈牙利算法的讲解博客有很多人讲的很详细了,我这里不再阐述。匈牙利算法
最大匹配数=最小点覆盖=总点数-最大独立集=总点数-最小路径点覆盖
证明在下面的对应的题目中

染色法判断二分图-关押罪犯

S S S城现有两座监狱,一共关押着 N N N 名罪犯,编号分别为 1 ∼ N 1∼N 1N
他们之间的关系自然也极不和谐。
很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。
我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。
如果两名怨气值为 c c c 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为 c c c 的冲突事件。
每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到 S S S Z Z Z 市长那里。
公务繁忙的 Z Z Z 市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。
在详细考察了 N N N 名罪犯间的矛盾关系后,警察局长觉得压力巨大。
他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。
假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。
那么,应如何分配罪犯,才能使 Z Z Z 市长看到的那个冲突事件的影响力最小?这个最小值是多少?

输入格式
第一行为两个正整数 N N N M M M,分别表示罪犯的数目以及存在仇恨的罪犯对数。
接下来的 M M M 行每行为三个正整数 a j aj aj b j bj bj c j cj cj,表示 a j aj aj 号和 b j bj bj 号罪犯之间存在仇恨,其怨气值为 c j cj cj
数据保证 1 ≤ a j < b j < N 1≤aj<bj<N 1aj<bj<N, 0 < c j ≤ 1 0 9 0<cj≤10^9 0<cj109 且每对罪犯组合只出现一次。

输出格式
输出共 1 1 1 行,为 Z Z Z 市长看到的那个冲突事件的影响力。
如果本年内监狱中未发生任何冲突事件,请输出 0 0 0

数据范围
N ≤ 20000 N≤20000 N20000, M ≤ 100000 M≤100000 M100000
输入样例:

4 6
1 4 2534
2 3 3512
1 2 28351
1 3 6618
2 4 1805
3 4 12884

输出样例:

3512

分析: 二分,染色法判断二分图 O ( ( N + M ) l o g C ) O((N+M)logC) O((N+M)logC)
将罪犯当做点,罪犯之间的仇恨关系当做点与点之间的无向边,边的权重是罪犯之间的仇恨值。那么原问题变成:将所有点分成两组,使得各组内边的权重的最大值尽可能小
看到最大值最小,我们就会想到二分了。
我们在 [ 0 , 1 0 9 ] [0,10^9] [0,109] 之间枚举最大边权 l i m i t limit limit,当 l i m i t limit limit 固定之后,剩下的问题就是:
能否将所有点分成两组,使得所有大于边权 l i m i t limit limit的边都在组间,而不在两组之内。所以这就是一个二分图的问题。判定所有大于边权limit的边所构成的新图是不是二分图
判断二分图可以用染色法。为了加速算法,我们来考虑是否可以用二分枚举 l i m i t limit limit,在用大于边权 l i m i t limit limit的边构成二分图之后,假定最终组内最大边权的最小值是 A n s Ans Ans:

  • 那么当 l i m i t ∈ [ a n s , 1 0 9 ] limit∈[ans,10^9] limit[ans,109] 时,所有边权大于 l i m i t limit limit 的边,必然是所有边权大于 A n s Ans Ans 的边的子集,肯定都分配在了组间,因此由此构成的新图也是二分图。
  • l i m i t ∈ [ 0 , a n s − 1 ] limit∈[0,ans−1] limit[0,ans1]时,由于 a n s ans ans 是新图可以构成二分图组内的最大边权的最小值,因此由大于 l i m i t limit limit 的边构成的新图一定不是二分图。
    所以整个区间具有二段性,可以二分出分界点 a n s ans ans 的值。

代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=200005,M=200005;
int n,m;
int e[M],w[M],ne[M],h[N],tot;
int color[N];//0表示未染色,1表示染白色,2表示染黑色
void add(int a,int b,int c)
    e[tot]=b,w[tot]=c,ne[tot]=h[a],h[a]=tot++;

bool dfs(int u,int c,int mid)
    color[u]=c;
    for(int i=h[u];~i;i=ne[i])
        int v=e[i];
        if(w[i]<=mid)continue;
        if(color[v])
            if(color[v]==c)return false;
        
        else if(!dfs(v,3-c,mid))return false;
    
    return true;

bool check(int mid)
    memset(color,0,sizeof(color));
    for(int i=1;i<=n;i++)
        if(!color[i])//开始染色
            if(!dfs(i,1,mid))return false;
        
    
    return true;

int main()

    scanf("%d %d",&n,&m);
    memset(h,-1,sizeof(h));
    for(int i=1;i<=m;i++)
        int a,b,c;scanf("%d %d %d",&a,&b,&c);
        add(a,b,c),add(b,a,c);
    
    int l=0,r=1e9;
    while(l<r)
        int mid=l+r>>1;
        if(check(mid))r=mid;
        else l=mid+1;
    
    printf("%d\\n",r);
    return 0;

最大匹配-棋盘覆盖

给定一个 N N N N N N 列的棋盘,已知某些格子禁止放置。

求最多能往棋盘上放多少块的长度为 2、宽度为 1 的骨牌,骨牌的边界与格线重合(骨牌占用两个格子),并且任意两张骨牌都不重叠。

输入格式
第一行包含两个整数 N N N t t t,其中 t t t 为禁止放置的格子的数量。

接下来 t t t 行每行包含两个整数 x x x y y y,表示位于第 x x x 行第 y y y 列的格子禁止放置,行列数从 1 开始。

输出格式
输出一个整数,表示结果。

数据范围
1 ≤ N ≤ 100 1≤N≤100 1N100,
0 ≤ t ≤ 100 0≤t≤100 0t100

输入样例:
8 0

输出样例:
32

分析: 这个题乍一看和二分图没什么关系

仔细分析,题目问最多能放多少个骨牌,使得任意两个骨牌都不重叠,意思就是能够取多少条边,使得所有选出来的边没有公共点。实际上就是找一个最大匹配。那么这个图是不是二分图呢?只有是二分图我们才能用匈牙利算法,二分图等价于能够二染色。
我们将所有的格子分成奇数格和偶数格,如下图所示,绿格和白格直接是有边的。绿格和绿格,白格和白格之间是没有边的。我们将所有的白格放一边,绿格放一边,所有的边必然是在两个集合之间的。所以这个图是二分图。

编号之后,偶数点是绿点,奇数点是白点

这个问题的难点就是如何转化为最大匹配问题

代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=105;
typedef pair<int,int>PII;
int n,t;
bool mp[105][105];
bool vis[105][105]以上是关于图论二分图的应用(染色法判断二分图,最大匹配,最小点覆盖,最大独立集,最小路径点覆盖,最小路径重复点覆盖)的主要内容,如果未能解决你的问题,请参考以下文章

图论 —— 二分图的判定及最大匹配

二分图的判定(染色法)和二分图最大匹配(匈牙利)算法及模板

四个点的圈是二分图吗

二分图算法手把手教你学会:染色法(判断二分图)匈牙利算法(二分图的最大匹配)

图论的一些知识点

第三章 搜索与图论