当前位置: 首页 > article >正文

二分图算法模板以及简单应用

染色法判断二分图

给定一个 n 个点 m 条边的无向图,图中可能存在重边和自环。

请你判断这个图是否是二分图。

输入格式

第一行包含两个整数 n 和 m。

接下来 m 行,每行包含两个整数 u 和 v,表示点 u 和点 v 之间存在一条边。

输出格式

如果给定图是二分图,则输出 Yes,否则输出 No

数据范围

1≤n,m≤10^5

输入样例:

4 4
1 3
1 4
2 3
2 4

输出样例:

Yes

二分图有个非常重要的性质:无奇数环。可以理解成一个充要条件:无奇数环的无向图一定是二分图,二分图一定没有奇数环

代码模板 

#include <iostream>
#include <vector>
#include <cstring>

using namespace std;

const int N = 1e5 + 10;
int color[N];
vector<int> e[N];

int n,m;

bool dfs(int u,int v){
    color[u] = v;
    
    for(auto x : e[u]){
        if(!color[x]){
            if(!dfs(x,3 - v)) return false;
        }else if(color[x] == v) return false;
    }
    
    return true;
}

int main()
{
    cin >> n >> m;
    for(int i = 0,a,b;i < m;i ++){
        cin >> a >> b;
        e[a].push_back(b),e[b].push_back(a);
    }
    
    bool check = true;
    for(int i = 1;i <= n;i ++){
        if(!color[i]){
            if(!dfs(i,1)){
                check = false;
                break;
            }
        }
    }
    
    if(check) cout << "Yes" << endl;
    else cout << "No" << endl;
    
    return 0;
}

二分图的最大匹配 

给定一个二分图,其中左半部包含 n1 个点(编号 1∼n1),右半部包含 n2 个点(编号 1∼n2),二分图共包含 m 条边。

数据保证任意一条边的两个端点都不可能在同一部分中。

请你求出二分图的最大匹配数。

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

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

输入格式

第一行包含三个整数 n1、 n2 和 m。

接下来 m 行,每行包含两个整数 u 和 v,表示左半部点集中的点 uu 和右半部点集中的点 vv 之间存在一条边。

输出格式

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

数据范围

1≤n1,n2≤500
1≤u≤n1
1≤v≤n2
1≤m≤10^5

输入样例:

2 2 4
1 1
1 2
2 1
2 2

输出样例:

2

匹配问题可以转换成找配偶问题,一个人只能找一个配偶,随便举个例子

比如我们要找这张图的最大匹配,一步步来从第一个点开始找

第一个点找到了配偶,但是他还有一个备选,看第二个点

第二个点也找到了,有一个备选

由于第三个点只有一个能选的,所以他把第二个点的配偶抢了,然后第二个去找了备选,这就是贪心的寻找最大匹配数量,剩下的所有点都是按这个方法找

代码模板

#include <iostream>
#include <vector>
#include <cstring>

using namespace std;

const int N = 510;
int match[N];
bool st[N];
vector<int> e[N];

int n1,n2,m;
int res = 0;

bool find(int u){
    for(auto x : e[u]){
        if(!st[x]){
            st[x] = true;
            if(!match[x] || find(match[x])){
                match[x] = u;
                return true;
            }
        }
    }
    
    return false;
}

int main()
{
    cin >> n1 >> n2 >> m;
    for(int i = 0,a,b;i < m;i ++){
        cin >> a >> b;
        e[a].push_back(b);
    }
    
    for(int i = 1;i <= n1;i ++){
        memset(st,false,sizeof(st));
        if(find(i)) res ++;
    }
    
    cout << res << endl;
    
    return 0;
}

封锁阳光大学

题目描述

曹是一只爱刷街的老曹,暑假期间,他每天都欢快地在阳光大学的校园里刷街。河蟹看到欢快的曹,感到不爽。河蟹决定封锁阳光大学,不让曹刷街。

阳光大学的校园是一张由 n 个点构成的无向图,n 个点之间由 m 条道路连接。每只河蟹可以对一个点进行封锁,当某个点被封锁后,与这个点相连的道路就被封锁了,曹就无法在这些道路上刷街了。非常悲剧的一点是,河蟹是一种不和谐的生物,当两只河蟹封锁了相邻的两个点时,他们会发生冲突。

询问:最少需要多少只河蟹,可以封锁所有道路并且不发生冲突。

输入格式

第一行两个正整数,表示节点数和边数。 接下来 m 行,每行两个整数 u,v,表示点 u 到点 v 之间有道路相连。

输出格式

仅一行如果河蟹无法封锁所有道路,则输出 Impossible,否则输出一个整数,表示最少需要多少只河蟹。

输入输出样例

输入 #1复制

3 3
1 2
1 3
2 3

输出 #1复制

Impossible

输入 #2复制

3 2
1 2
2 3

输出 #2复制

1

说明/提示

【数据规模】
对于 100%的数据,1≤n≤10^4,1≤m≤10^5,保证没有重边。

这道题是一个染色法判断二分图的一个简单应用,首先如果有奇数环,那说明不可能满足题目条件(非常悲剧的一点是,河蟹是一种不和谐的生物,当两只河蟹封锁了相邻的两个点时,他们会发生冲突。)所以先判断这张图是否是二分图,下一步因为二分图只有两种颜色,定义为1和2(看个人习惯吧)我们只需要在每一个连通块当中找min(cnt_1,cnt_2)加到res当中就是答案了

代码

#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1e4 + 10;
int color[N];
vector<int> e[N];

int n,m;
int res = 0;

bool dfs(int u,int v,int &cnt1,int &cnt2){
    if(v == 1) cnt1 ++;
    else cnt2 ++;

    color[u] = v;
    for(auto x : e[u]){
        if(!color[x]){
            if(!dfs(x,3 - v,cnt1,cnt2)) return false;
        }else if(color[x] == v) return false;
    }

    return true;
}

int main()
{
    cin >> n >> m;
    for(int i = 0,a,b;i < m;i ++){
        cin >> a >> b;
        e[a].push_back(b),e[b].push_back(a);
    }

    bool check = true;
    for(int i = 1;i <= n;i ++){
        if(!color[i]){
            int cnt1 = 0,cnt2 = 0;
            if(!dfs(i,1,cnt1,cnt2)){
                check = false;
                break;
            }
            res += min(cnt1,cnt2);
        }
    }

    if(!check){
        cout << "Impossible" << endl;
        return 0;
    }

    cout << res << endl;

    return 0;
}

加油 


http://www.kler.cn/a/321111.html

相关文章:

  • C++中特殊类设计/单例模式
  • 基于Spring Boot的电子商务系统设计
  • 软件设计师 - 第1章 计算机网络概论
  • 数据分析-48-时间序列变点检测之在线实时数据的CPD
  • 【安全科普】NUMA防火墙诞生记
  • 摄像机视频分析软件下载LiteAIServer视频智能分析软件抖动检测的技术实现
  • 电气自动化入门03:安全用电
  • 那年我双手插兜,使用IPv6+DDNS动态域名解析访问NAS
  • 数据清洗与数据治理的关系
  • 科研绘图系列:R语言树结构聚类热图(cluster heatmap)
  • NLP基础1
  • PostgreSQL 的log_hostname 参数测试
  • 搭建cdh集群及问题处理
  • HandlerInterceptor这个类有什么作用?
  • 基于JAVA+SpringBoot+Vue的健身房管理系统1
  • Redis Sorted Set 跳表的实现原理和分析
  • 数据结构升华部分:排序与字符串匹配算法应用
  • 产品经理面试整理-练习常见面试问题
  • 【Linux】Linux 的 权限
  • 钉钉 钉钉打卡 钉钉定位 2024 免费试用 保用
  • 【运维】微软官方包管理器winget的使用, 对比scoop/choco(含常用软件清单,本地镜像源自建,静默安装教程)
  • Spring Boot 中整合 Kafka
  • EAGLE——探索混合编码器的多模态大型语言模型的设计空间
  • BOE(京东方)重磅亮相世界制造业大会 科技创新引领现代化产业体系建设新未来
  • Tengine 容器
  • HTML开发指南