IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 神机百炼3.54-染色法判定二分图 -> 正文阅读

[数据结构与算法]神机百炼3.54-染色法判定二分图

染色法导图

食用指南:

对该算法程序编写以及踩坑点很熟悉的同学可以直接跳转到代码模板查看完整代码
只有基础算法的题目会有关于该算法的原理,实现步骤,代码注意点,代码模板,代码误区的讲解
非基础算法的题目侧重题目分析,代码实现,以及必要的代码理解误区

题目描述:

  • 给定一个二分图,其中左半部包含 n1 个点(编号 1~n1),右半部包含 n2 个点(编号 1~n2),二分图共包含 m 条边。
    数据保证任意一条边的两个端点都不可能在同一部分中。
    请你求出二分图的最大匹配数。

    二分图的匹配:给定一个二分图 G,在 G 的一个子图 M 中,M 的边集 {E} 中的任意两条边都不依附于同一个顶点,则称 M 是一个匹配。
    二分图的最大匹配:所有匹配中包含边数最多的一组匹配被称为二分图的最大匹配,其边数即为最大匹配数。

    输入格式
    第一行包含三个整数 n1、 n2 和 m。
    接下来 m 行,每行包含两个整数 u 和 v,表示左半部点集中的点 u 和右半部点集中的点 v 之间存在一条边。

    输出格式
    输出一个整数,表示二分图的最大匹配数。

    数据范围
    1≤n1,n2≤500,
    1≤u≤n1,
    1≤v≤n2,
    1≤m≤105
    输入样例:
    2 2 4
    1 1
    1 2
    2 1
    2 2
    输出样例:
    2

  • 题目来源:https://www.acwing.com/problem/content/863/

题目分析:

  • 染色法经典题目:针对每点,若将其染为x色,则将其邻接点染为另一色。
    最终图中每一点都成功着色,则该图为二分图。
    反之若某点出现染色矛盾,既应该染x色,又应该染另一色,则该图不为二分图。
  • 染色法分为两种:dfs实现 & bfs实现
    下面来讲同为O(n)的两种染色法判定二分图

算法原理:

模板算法:

染色法:

1. 二分图:

  • 定义:
    对于每一条边,将其两个端点放置在不同的两个集合中。
    若最终图中所有点完美被划分到两个不同集合中,则该图为二分图。
  • 性质:
    可以用两种颜色无冲突的着色图中所有点。
  • 举例:
    二分图:
    二分图
    非二分图:
    非二分图

2. 两大步骤:

  • 对于每一个点,不论dfs还是bfs,任务有二:

    为当前未着色点着色 & 查看邻接点和当前点是否存在冲突。

  1. 为当前未着色的x点染色y:

  2. 遍历当前x点的邻接点,逐个判断是否与当前点冲突:

    若邻接点已经着色,且为y,则出现着色冲突,直接判定非二分图

    若邻接点已经着色,且为y的对立色,则继续为下一个邻接点着色。

    若邻接点未着色,则将其染色为y的对立色,之后继续为下一个邻接点着色。

代码实现:

dfs实现染色法

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 200020;   //m条边,则2m个点
int color[N];           //标记每个点的颜色,二分图只需1 & 2两种颜色
int h[N], val[N], ne[N];
int idx;
void add(int x, int y){
    val[idx] = y;
    ne[idx] = h[x];
    h[x] = idx++;
}
int n,m;
bool dfs(int x, int y){
    color[x] = y;
    for(int i = h[x]; i!=-1; i=ne[i]){
        if(color[val[i]] == y){		//检查已着色点是否含有着色冲突
            return false;
        }else if(!color[val[i]]){	//为未着色点着色
			if(!dfs(val[i],3-y))
                return false;
        }
        
    }
    return true;
}
int main(){
    memset(h, -1, sizeof(h));
    cin >>n >>m;
    int a = 0, b = 0;
    while(m--){
        cin >>a >>b;
        add(a, b);
        add(b, a);
    }
    //可能是非连通图,每个连通分量都需要染色
    for(int i=1; i<=n; i++){
        if(!color[i]){
            if (!dfs(i,1)){
                cout << "No"<<endl;
                return 0;
            }
        }
    }
    cout <<"Yes"<<endl;
    return 0;
}

bfs实现染色法:

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 200020;
int h[N], val[N], ne[N];
int idx;
void add(int x, int y){
    val[idx] = y;
    ne[idx] = h[x];
    h[x] = idx++;
}
int n, m;
int color[N];
int tt = 0, hh = 0;
int que[N];
bool bfs(int x, int y){
    que[tt++] = x;		//从que[0]开始存储
    color[x] = y;
    while(hh < tt){		//开始hh==tt==0时,队列为空;所以只有hh<tt时队列中含有元素
        int t = que[hh++];
        for(int i=h[t]; i!=-1; i=ne[i]){
            if (color[val[i]] == color[t]){		//检查已着色相邻点是否存在颜色冲突
                return 0;
            }else if (!color[val[i]]){			//为未着色的点着色
                color[val[i]] = 3-color[t];
                que[tt++] = val[i];
            }
        }
    }
    return 1;
}
int main(){
    memset(h, -1, sizeof h);
    cin >>n >>m;
    int a=0, b=0;
    while(m--){
        cin >>a >>b;
        add(a, b);
        add(b, a);
    }
    //非连通图的每个连通分量都需要染色
    for(int i=1; i<=n; i++){
        if (!color[i]){
            if (!bfs(i, 1)){
                cout<< "No";
                return 0;
            }
        }
    }
    cout<< "Yes";
    return 0;
}

代码误区:

1. 两种颜色的转换技巧:

  • 假设两种颜色为x色和y色,且记x+y的和为s
    这一点染色为x,则下一点染色为s-x

2. 易漏点:非连通图

  • 当已经对全图中一点进行染色法,但是仍存在某些点未被着色,说明图是非连通图。
  • 对于非连通图的每一个连通分量,选择其中一点进行染色法。
  • 每进行一次染色法,都要继续遍历所有点,检查是否还存在未被染色的连通分量。

3. DFS和BFS的相同点:

  • 都是在给未染色的点着色时,发现这一点与已染色的相邻点发生了冲突。

本篇感想:

  • 染色法本身理解和实现都较为简单,只需记住两点:

    给未染色的点染色 & 检查当前点是否和已染色的相邻点发生染色冲突。

  • 看完本篇博客,恭喜已登 《筑基境-后期》
    筑基境

距离登仙境不远了,加油 登仙境初期

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-07-05 23:40:24  更:2022-07-05 23:41:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 23:19:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码