本文概论


二分图的判断方法:图中不存在奇数环----->染色法判断二分图不存在矛盾
二分图:
设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。
染色判断:
二分图判断可分为:连通图判断和非连通图判断
染色思路:
1)初始所有定点未染色
2)随意取出一个未染色的顶点u,把它染成一种颜色(假设为0)。
3)取出与它连接的结点v,如果v未染色,则将v染成和u不同的颜色(假设为1),如果v已经染色,那么判断u和v颜色是否相同,相同则表明染色失败,该图不是二分图,结束。
4)遍历所有结点,重复步骤3)
5)连通图只需要一次dfs染色,非连通图则多次dfs染色。

Acwing257. 关押罪犯

题目大意:就是每两个罪犯之间有一个冲突值c,如果把他们关到同一个监狱就会引起威力为c的冲突,现在有两个监狱,如何分配罪犯始得两个监狱内冲突最大值最小
1.很明显这是一个二分图问题,我们尽可能的把大边的两端点放到两个不同的集合;2.对于最大值最小问题我们可以二分来做;3.我们如何check对于小于mid的边我们可以不跑就说意向上的删除continue

#include <iostream>
#include <cstdio>
#include <stack>
#include <sstream>
#include <vector>
#include <map>
#include <cstring>
#include <deque>
#include <cmath>
#include <iomanip>
#include <queue>
#include <algorithm>
#include <set>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define _for(i,a,b) for( int i = (a); i < (b); ++i)
#define _rep(i,a,b) for( int i = (a); i <= (b); ++i)
#define for_(i,a,b) for( int i = (a); i >= (b); -- i)
#define rep_(i,a,b) for( int i = (a); i > (b); -- i)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define hash Hash
#define next Next
#define count Count
#define pb push_back
#define f first
#define s second
using namespace std;
const int N = 1e5+10, mod = 10007;
const double eps = 1e-10;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
inline LL read()
{LL f=1,s=0;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+ch-'0',ch=getchar();return s*f;
}
int n,m;
int a[N];
struct node {int to, next, w;
}e[N << 2];
int head[N << 2], cnt;
int color[N << 2];
inline void add(int from, int to, int w)
{e[cnt] = {to,head[from],w};head[from] = cnt ++;
}bool dfs(int u, int c, int Mid)
{color[u] = c;for(int i = head[u]; ~i; i = e[i].next){int v = e[i].to;if(e[i].w <= 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)
{ms(color,0);for(int i = 1; i <= n; ++ i)if(!color[i])if(!dfs(i,1,Mid)) return false;return true;
}int main()
{n = read(), m = read();ms(head,-1);while(m --){int l , r, w;l = read(), r = read(), w = read();add(l,r,w), add(r,l,w);}int l = 0, r = 1e9;while(l < r){if(check(mid)) r = mid;else l = mid + 1;}printf("%d\n",l);return 0;
}

2)匈牙利算法:(二分图是前提)

增广路径:从非匹配点->非匹配边->匹配边-。。。。。->非匹配点;
最大匹配—>不存在增广路径
Acwing372. 棋盘覆盖

给定一个N行N列的棋盘,已知某些格子禁止放置
求最多能往棋盘上放多少块的长度为2、宽度为1的骨牌,骨牌的边界与格线重(骨牌占用两个格子),并且任意两张骨牌都不重叠。

我们可以这样想因为对于棋盘上的每一个格子我们可以看成一个点,我们放置骨牌我们就连边,题目就可以变成我们最多选多少个点达到最大边数就是最大匹配
判断是否为二分图
##二分图基础代码
这就是匈牙利算法的流程,其中找妹子是个递归的过程,最最关键的字就是“腾”字
其原则大概是:有机会上,没机会创造机会也要上

for (i=1;i<=n;i++)
{memset(used,0,sizeof(used));    //这个在每一步中清空if find(i) all+=1;
}bool find(int x){int i,j;for (j=1;j<=m;j++){    //扫描每个妹子if (line[x][j]==true && used[j]==false)      //如果有暧昧并且还没有标记过(这里标记的意思是这次查找曾试图改变过该妹子的归属问题,但是没有成功,所以就不用瞎费工夫了){used[j]=1;if (girl[j]==0 || find(girl[j])) { //名花无主或者能腾出个位置来,这里使用递归girl[j]=x;return true;}}}return false;
}

匈牙利算法只需要从一端开始匹配我们可以从奇数点开始去匹配


将格子染色,奇数点和偶数点都分别处在不同颜色

#include <iostream>
#include <cstdio>
#include <stack>
#include <sstream>
#include <vector>
#include <map>
#include <cstring>
#include <deque>
#include <cmath>
#include <iomanip>
#include <queue>
#include <algorithm>
#include <set>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define _for(i,a,b) for( int i = (a); i < (b); ++i)
#define _rep(i,a,b) for( int i = (a); i <= (b); ++i)
#define for_(i,a,b) for( int i = (a); i >= (b); -- i)
#define rep_(i,a,b) for( int i = (a); i > (b); -- i)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define hash Hash
#define next Next
#define count Count
#define pb push_back
#define f first
#define s second
using namespace std;
const int N = 110, mod = 10007;
const double eps = 1e-10;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
inline LL read()
{LL f=1,s=0;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+ch-'0',ch=getchar();return s*f;
}
int n, m;
PII match[N][N];
bool g[N][N], st[N][N];int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};bool find(int x, int y)
{_for(i,0,4){int a = x + dx[i], b = y + dy[i];if(a < 1 || b < 1 || a > n || b > n) continue;if(st[a][b] || g[a][b]) continue;PII t = match[a][b];st[a][b] = true;if(t.f == 0 || find(t.f, t.s)){match[a][b] = {x,y};return true;}}return false;
}int main()
{cin >> n >> m;while(m --){int x, y;cin >> x >> y;g[x][y] = true;}int res = 0;_for(i,1,n+1)_for(j,1,n+1)if((i + j) % 2 && !g[i][j]){ms(st,0);if(find(i,j)) res ++;}cout << res << endl;return 0;
}

3)最大匹配数 = 最小点覆盖 = 总点数 - 最大独立集 = 总点数 - 最小路径覆盖

二分图中最小点覆盖 = 最大匹配数

最小点覆盖就是挑出最少的点去覆盖所有的边(覆盖的意思就是这条边至少要有一个端点被选中)

376. 机器任务

#include <iostream>
#include <cstdio>
#include <stack>
#include <sstream>
#include <vector>
#include <map>
#include <cstring>
#include <deque>
#include <cmath>
#include <iomanip>
#include <queue>
#include <algorithm>
#include <set>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define _for(i,a,b) for( int i = (a); i < (b); ++i)
#define _rep(i,a,b) for( int i = (a); i <= (b); ++i)
#define for_(i,a,b) for( int i = (a); i >= (b); -- i)
#define rep_(i,a,b) for( int i = (a); i > (b); -- i)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define hash Hash
#define next Next
#define count Count
#define pb push_back
#define f first
#define s second
using namespace std;
const int N = 110, mod = 10007;
const double eps = 1e-10;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
inline LL read()
{LL f=1,s=0;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+ch-'0',ch=getchar();return s*f;
}
int n, m, k;
int match[N];
bool g[N][N], st[N];bool find(int x)
{_for(i,1, m)if(!st[i] && g[x][i]){st[i] = true;int t = match[i];if(t == 0 || find(t)){match[i] = x;return true;}}return false;
}int main()
{while(cin >> n ,n){cin >> m >> k;ms(g,0);ms(match,0);while(k --){int t, a, b;cin >> t >> a >> b;if(!a || !b) continue;g[a][b] = true;}int res = 0;_for(i,1,n){ms(st,0);if(find(i)) res ++;}cout << res << endl;}return 0;
}


4)最大独立集:选出最多的点,使得选出的点之间没有边—>去掉最少的点把所有的边都破坏掉–>总点数 - 找最小点颠覆

378. 骑士放置
题目大意:给定一个 N*M 的棋盘,有一些格子禁止放棋子。
问棋盘上最多能放多少个不能互相攻击的骑士(国际象棋的“骑士”,类似于中国象棋的“马”,按照“日”字攻击,但没有中国象棋“别马腿”的规则)。

1.不能相互攻击抽象成所选的点不会有边
2.划分为奇数点和偶数点,将点分成两个集合

#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 105;
int dx[8] = {-2, -2, 2, 2, -1, -1, 1, 1};
int dy[8] = {-1, 1, -1, 1, -2, 2, -2, 2};
bool g[N][N], vis[N][N];
int n, m, t, x, y;
pair<int, int> mat[N][N];
bool dfs(int x, int y) {for (int i = 0; i < 8; i++) {int fx = x + dx[i], fy = y + dy[i];if (fx <= 0 || fy <= 0 || fx > n || fy > m || g[fx][fy] || vis[fx][fy]) continue; vis[fx][fy] = true; int px = mat[fx][fy].first, py = mat[fx][fy].second;if ((!px && !py) || dfs(px, py)) {mat[fx][fy] = make_pair(x, y); return true;}}return false;
}
int main() {scanf("%d%d%d", &n, &m, &t);for (int i = 1; i <= t; i++) {scanf("%d%d", &x, &y); g[x][y] = 1;}int ans = 0;for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {if (g[i][j] || ((i + j) & 1)) continue;memset(vis, false, sizeof(vis));if (dfs(i, j)) ans++;}}printf("%d\n", n * m - t - ans);return 0;
}

5)最小路径点覆盖:

定义:在一个有向图中,找出最少的路径,使得这些路径经过了所有的点。
最小路径覆盖分为1最小不相交路径覆盖和2最小可相交路径覆盖。
1.最小不相交路径覆盖:每一条路径经过的顶点各不相同。如图,其最小路径覆盖数为3。即1->3>4,2,5。
2.最小可相交路径覆盖:每一条路径经过的顶点可以相同。如果其最小路径覆盖数为2。即1->3->4,2->3>5。
3.特别的,每个点自己也可以称为是路径覆盖,只不过路径的长度是0。

算法:把原图的每个点V拆成VxVx和VyVy两个点,如果有一条有向边A->B,那么就加边Ax−>ByAx−>By。这样就得到了一个二分图。那么最小路径覆盖=原图的结点数-新图的最大匹配数。
证明:一开始每个点都是独立的为一条路径,总共有n条不相交路径。我们每次在二分图里找一条匹配边就相当于把两条路径合成了一条路径,也就相当于路径数减少了1。所以找到了几条匹配边,路径数就减少了多少。所以有最小路径覆盖=原图的结点数-新图的最大匹配数。
因为路径之间不能有公共点,所以加的边之间也不能有公共点,这就是匹配的定义。


因为最小路径不重复点覆盖的:选出的路径上没有相交的点那么选出的路径上的点的都是只属于一条路的,由于是又向无环图那么最后一个一定不可以到达其他点。

首先,最小路径覆盖=总节点数-最大匹配数。这个应该已经是路人皆知了。
所谓最小路径覆盖,是指在一个有向图中,找出最少的几条路径,用它们来覆盖全图这里说的值得注意的地方,如果有向图的边有相交的情况,那么就不能简单的对原图求二分匹配了
举个例子,假设有图:1->2 2->5 2->3 4->2,事实上,这其实就是两条边:1->5 4->3 ,节点2只是他们的一个交点


如果只是简单的在原图的基础上求二分匹配,那么得到的匹配答案是2,最小路径覆盖答案便是5-2=3。
可是随便一看都能看看出端倪,这个图中,只需要两个点便可以探索完整个地图,这里最小路径覆盖数明显是2。
问题究竟出在哪里呢?其实就和这个交点2有关。既然边有相交,那么他们的连通性也应该连通下去。
解决的办法是对原图进行一次闭包传递(也就是flody),于是便增加了四条边:1->3 1->5 4->3 4->5
这时再求最大匹配数,匹配答案便是3,最小路径覆盖值为2,这是正确答案!

二分图专题系列各大知识点总结(匈牙利,染色法,最大独立集,最小点覆盖,最小路径覆盖)相关推荐

  1. 二分图----最大匹配,最小点覆盖,最大点独立集

    一.二分图 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不 ...

  2. java 分布式计算框架_学Java分布式和高级架构,必懂的两大知识点!

    原标题:学Java分布式和高级架构,必懂的两大知识点! 第一部分:分布式 三步变成:分布式 1.将你的整个软件视为一个系统(不管它有多复杂) 2.将整个系统分割为一系列的 Process(进程), 每 ...

  3. 专题导读:大数据支撑的智能应用

    点击上方蓝字关注我们 信息技术的发展使得数据采集.存储.管理等成本下降,同时也给机器学习等人工智能方法提供了足够的训练样本,使大数据成为人工智能发展的三大重要基础(数据.算法和算力).在近年来大数据技 ...

  4. c语言二分法查找一个数_算法竞赛小专题系列(1):二分法、三分法

    本系列是这本算法教材的扩展资料:<算法竞赛入门到进阶>. 罗勇军.郭卫斌. 清华大学出版社 二分法和三分法是算法竞赛中常见的算法思路,本文介绍了它们的理论背景.模板代码.典型题目. 1. ...

  5. ORAN专题系列-1:什么是开放无线接入网O-RAN

    这篇文章将回答如下几个问题:什么是无线接入网RAN? 什么是开放无线接入网ORAN? ORAN与5G的关系? ORAN提出的动机?ORAN的参与方?以及ORAN的技术目标?ORAN联盟的组织架构? 目 ...

  6. ORAN专题系列-0: O-RAN快速索引

    专题一:O-RAN的快速概述 <ORAN专题系列-1:什么是开放无线接入网O-RAN>ORAN专题系列-1:什么是开放无线接入网O-RAN_文火冰糖的硅基工坊的博客-CSDN博客_什么是o ...

  7. 20200918:【广发金融工程】2018年重磅专题系列之九:基于隐马尔科夫模型的选股策略研究

    参考链接:https://www.sohu.com/a/252454782_465470 [广发金融工程]2018年重磅专题系列之九:基于隐马尔科夫模型的选股策略研究 2018-09-07 11:26 ...

  8. 视频教程-思科CCNP专题系列13:IP多播协议-思科认证

    思科CCNP专题系列13:IP多播协议 新任帮主,双CCIE(CCIE R&S,CCIE Security):2011年前在国内知名培训机构担任CCIE R&S讲师:因一直秉持知行统一 ...

  9. 视频教程-思科CCNP专题系列10:MPLS Virtual PN-思科认证

    思科CCNP专题系列10:MPLS Virtual PN 新任帮主,双CCIE(CCIE R&S,CCIE Security):2011年前在国内知名培训机构担任CCIE R&S讲师: ...

最新文章

  1. spring_security权限应用
  2. 一、Windows Server 2016 AD服务器搭建
  3. JAVA——GZIP压缩与解压缩
  4. 介绍家乡网页html代码_「HTML一」 html基础
  5. java c3p0 存储过程_JAVA Spring 连接池 调用 Oracle 存储过程的问题?
  6. js基础-22-基本数据类型不是对象
  7. 目标检测->SSD算法
  8. java 开根号函数_java如何开根号?
  9. python+gdal+numpy实现影像uint16转uint8
  10. 【OpenBMC 系列】3.bitbake介绍
  11. LVS_DR+keepalived(内涵理论与实验)
  12. 【操作系统】知识梳理(十一)多媒体操作系统
  13. Sulley fuzzer learning
  14. 【微服务实战之Docker容器】第一章-下载及安装
  15. SQL注入——SQL注入具体防御方案
  16. 序列化和反序列化二叉树 -----前序,中序,后序,层序
  17. 狂奔的“智慧校园”:监控学生的生意,会持续吗?
  18. 创建windows 窗口
  19. 信息学奥赛系列教程:高精度计算
  20. JS获取新浪实时股票行情数据

热门文章

  1. 在C++平台上部署PyTorch模型流程+踩坑实录
  2. 技能 | Python处理图像10大经典库
  3. 用于RGB-D语义分割的全局-局部传播网络
  4. 基于OpenCV的多位数检测器
  5. 可见面判别算法---可见面判别算法的分类
  6. Ubuntu 16.04 LTS GNOME版本下载
  7. 开源项目OpenGene发起人:用“互联网+基因技术”改变肿瘤的诊断与治疗
  8. QPushButton 响应回车 设置默认按钮
  9. python中的匿名函数与lambda
  10. 关于PPP Multilink协议的配置