二分图

终极模板“水题”——网络流

怎甘沉沦 提交于 2019-12-04 16:16:52
其实这篇https://www.cnblogs.com/victorique/p/8560656.html写得很完整了,但是为了加深自己的印象,就自己写一篇吧。 网络流的练习我用了传说中的网络流24题,我把题目都看了一遍,发现一个问题,有些题好像真的是为了网络流而搞网络流的做法出来,导致题目的可做性不强,虽然如此,但是除了这些题目之外,其他的题目,也挺让我耳目一新的。 其实,网络流把两套模板给记住,基本上就算是完成了一道题的一大半了。第一套模板是网络最大流(dinic+当前弧优化);第二套模板是最小费用最大流(利用spfa找出最短路的同时保证网络最大流)但是如果像我这么说的话,把网络流单纯看成模板题,是肯定是做不出来题目的,那么网络流关键的点在哪?网络流通常的套路又是什么? 1.建图 基本上网络流的题都难在这里了。如何建图,是一个难点。 (1)二分图 一类建图即是以二分图的形式来建,其包括操作拆点,建立超级源点、汇点,等等。那么在二分图上,能进行解决什么问题呢?最普遍的莫过于匹配问题,通过二分图,求出点与点之间的最大匹配值,然后再利用二分图上的性质,来求出问题的解,而二分图上的性质有下面几种常用的:最大匹配=最小点覆盖;最小路径覆盖=|G|-最大匹配数(G为点数);最大独立集=点数-最大匹配=最小边覆盖。我们可以看到求出一个最大匹配,基本上就能算出其他的问题出来

11.5 AM 请求

血红的双手。 提交于 2019-12-03 15:25:52
题意 给定一个图,请把它分为两个子图,使得每一个子图都是完全图;并且要求这两个图的边数之和最少 解法 先建出原图的反图,即有边连接的两个点之间不连边,没有边连接的两个点之间连一条边 可以发现这个图可以被拆成两个完全图当且仅当每一个联通块都是一个二分图 因为如果不是二分图(存在奇环)的话,一定有奇数个点之间互不连边,那么无论如何也无法把它们分入两个集合使得这两个集合均为完全图 二分图染色后的新图中,同一个联通块且是相同颜色的点一定在同一个子图中,而不同联通块中即使颜色不同也可以放在一起,因为两个联通块中的点一定是互有连边的 设 \(f_i\) 表示是否存在一个分组方式使得其中有一组的大小为 \(i\) ,枚举联通块背包转移即可 代码 #include <cstdio> #include <cctype> #include <bitset> #include <cstring> #include <iostream> using namespace std; const int MAX_N = 800; const int MAX_M = 700000; int read(); typedef bitset<MAX_N> Bit; int N, M, fl, cnt; int col[MAX_N], sz[2]; int head[MAX_N], to[MAX_M], nxt[MAX

Card Collector AtCoder - 5168(二分图匹配的HALL定理)

回眸只為那壹抹淺笑 提交于 2019-12-03 14:50:20
题意: 给定一个H行W列的矩阵,在矩阵的格点上放带权值的卡片(一个点上能放多张)。 现在从每行每列各拿走一张卡片(没有可以不拿),求可以拿到的最大权值。 卡片数N<=1e5,H,W<=1e5 思路: 显然可以构造成一个最大费用流模型:每张卡片到它对应的行列各有一条费用0,容量1的边;源点到每张卡片有一条费用为卡片权值,容量1的边;每个行列到汇点有一条费用0,容量1的边。但是边数有5e5,应该会超时吧? 观察这个图发现除去源点和汇点是一张二分图,想到是否可以利用二分图的性质简化问题。 手动模拟一波发现好像只要贪心地从大到小拿,能拿则拿,那么就能得到最佳答案。如何检测是否还能拿呢? HALL定理:如果一个二分图上,左部|X|<=右部|Y|,如果左部点的任意一个子集U,U相连边对应右部的子集V都有|U|<=|V|,那么这个二分图有最大匹配|X|。 每次拿走点相当于在U中增加点,在V中增加边,用并查集维护一下集合的大小即可。 所在行列在同个集合中,直接判断这个集合是否满足条件 所在行列不在同一个集合中,那么判断这两个集合合并后是否满足条件,若是则合并 #include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=2e5+5; struct node{ int r,c,a; friend

最小路径覆盖问题

匿名 (未验证) 提交于 2019-12-03 00:39:02
byvoid好神啊Orz 摘自byvoid的题解 【问题分析】 有向无环图最小路径覆盖,可以转化成二分图最大匹配问题,从而用最大流解决。 【建模方法】 构造二分图,把原图每个顶点i拆分成二分图X,Y集合中的两个顶点Xi和Yi。对于原图中存在的每条边(i,j),在二分图中连接边(Xi,Yj)。然后把二分图最大匹配模型转化为网络流模型,求网络最大流。 最小路径覆盖的条数,就是原图顶点数,减去二分图最大匹配数。沿着匹配边查找,就是一个路径上的点,输出所有路径即可。 【建模分析】 对于一个路径覆盖,有如下性质: 1、每个顶点属于且只属于一个路径。 2、路径上除终点外,从每个顶点出发只有一条边指向路径上的另一顶点。 所以我们可以把每个顶点理解成两个顶点,一个是出发,一个是目标,建立二分图模型。该二分图的任何一个匹配方案,都对应了一个路径覆盖方案。如果匹配数为0,那么显然路径数=顶点数。每增加一条匹配边,那么路径覆盖数就减少一个,所以路径数=顶点数 - 匹配数。要想使路径数最少,则应最大化匹配数,所以要求二分图的最大匹配。 注意,此建模方法求最小路径覆盖仅适用于有向无环图,如果有环或是无向图,那么有可能求出的一些环覆盖,而不是路径覆盖。 #include <queue> #include <cstdio> #include <cstring> const int N=3550,inf

二分图详解

匿名 (未验证) 提交于 2019-12-03 00:18:01
先介绍一下基本概念 以下基本概念转自其他的博客,不是原创 二分图 匹配 :在图论中,一个「匹配」(matching)是一个边的集合,其中任意两条边都没有公共顶点。例如,图 3、图 4 中红色的边就是图 2 的匹配 我们定义 匹配点 、 匹配边 、 未匹配点 、 非匹配边 ,它们的含义非常显然。例如图 3 中 1、4、5、7 为匹配点,其他顶点为未匹配点;1-5、4-7为匹配边,其他边为非匹配边。 最大匹配 :一个图所有匹配中,所含匹配边数最多的匹配,称为这个图的最大匹配。图 4 是一个最大匹配,它包含 4 条匹配边。 完美匹配 :如果一个图的某个匹配中,所有的顶点都是匹配点,那么它就是一个完美匹配。图 4 是一个完美匹配。显然,完美匹配一定是最大匹配(完美匹配的任何一个点都已经匹配,添加一条新的匹配边一定会与已有的匹配边冲突)。但并非每个图都存在完美匹配。 上述是基本概念,接下来讲一下为匈牙利算法服务的一些概念 交替路 :从一个未匹配点出发,依次经过非匹配边、匹配边、非匹配边...形成的路径叫交替路。 增广路 :从一个未匹配点出发,走交替路,如果途径另一个未匹配点(出发的点不算),则这条交替路称为增广路(agumenting path)。例如,图 5 中的一条增广路如图 6 所示(图中的匹配点均用红色标出): 增广路有一个重要特点:非匹配边比匹配边多一条。因此,研究增广路的意义是

网络流24题の详解

匿名 (未验证) 提交于 2019-12-03 00:02:01
把网络流24题刷完我就算萌新了。 (持续更新直到刷完为止) \(1.\) 洛谷P2756 飞行员配对方案问题 题意:派出最多架的飞机,并且每架飞机上都是一个英国飞行员和外籍飞行员 分析:经典的二分图匹配问题,将英国飞行员当做二分图的左部,外籍飞行员当做二分图的右部。可以用匈牙利算法求解,但这里使用网络流(最大流)。 考虑如何建图: 设立一个源点 \(st\) ,一个汇点 \(ed\) 。 \(I.\) 让源点 \(st\) 向二分图的左部建一条流量为 \(1\) 的边, \(II.\) 让二分图的右部向汇点 \(ed\) 建一条流量为 \(1\) 的边, \(III.\) 如果英国飞行员 \(u\) 可以和外籍飞行员 \(v\) 配合,那么 \(u\) 和 \(v\) 建一条流量为 \(1\) 的边。 最后跑一遍最大流即可得到最大匹配数。 如何输出配对方案: 遍历所有的英国飞行员所连的边,如果此边 \((u,v)\) 流量不是 \(1\) 而是 \(0\) 说明 \((u,v)\) 配对。注意源点向英国飞行员所连的边流量会为0,但此时不应输出。 #include <bits/stdc++.h> using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef pair<int,

LeetCode 785. 判断二分图

匿名 (未验证) 提交于 2019-12-02 23:48:02
给定一个无向图graph,当这个图为二分图时返回true。 如果我们能将一个图的节点集合分割成两个独立的子集A和B,并使图中的每一条边的两个节点一个来自A集合,一个来自B集合,我们就将这个图称为二分图。 示例 1: 输入: [[1,3], [0,2], [1,3], [0,2]] 输出: true 解释: 无向图如下: 0----1 3----2 我们可以将节点分成两组: {0, 2} 和 {1, 3}。 示例 2: 输入: [[1,2,3], [0,2], [0,1,3], [0,2]] 输出: false 解释: 无向图如下: 0----1 3----2 我们不能将节点分割成两个独立的子集。 注意: graph 的长度范围为 [1, 100]。 graph[i] 中的元素的范围为 [0, graph.length - 1]。 graph[i] 不会包含 i 或者有重复的值。 图是无向的: 如果j 在 graph[i]里边, 那么 i 也会在 graph[j]里边。 算法:BFS。 class Solution { public: bool bfs(int k, vector<int>& s, vector<vector<int>>& g){ s[k]=0; queue<int>q; q.push(k); while(q.size()){ int u=q.front(); q

[LuoguP1155]双栈排序_二分图_bfs

孤者浪人 提交于 2019-12-02 20:10:20
双栈排序 题目链接 : https://www.luogu.org/problem/P1155 数据范围 :略。 题解 : 神仙题。 就第一步就够劝退了。 这个二分图非常不容易,首先只有两个栈,不是属于一个就是属于另一个,我们用二分图判断冲突。 然后不能模拟,我们就贪心的bfs就行了,这一步很鬼畜啊.... 来源: https://www.cnblogs.com/ShuraK/p/11762283.html

luogu_1155: 双栈排序

夙愿已清 提交于 2019-12-02 16:51:05
洛谷1155:双栈排序 题意描述: 给定一个长度为 \(n\) 的序列 \((n\leq 1000)\) ,两个初始为空的栈,问是否能借助以下四种操作将序列排为升序。 \(1:\) 如果序列不为空,将第一个元素压入栈 \(S_1\) 。记为操作 \(a\) 。 \(2:\) 如果栈 \(S_1\) 不为空,将 \(S_1\) 栈顶元素弹出至输出序列。记为操作 \(d\) 。 \(3:\) 输入序列不为空,将第一个元素压入栈 \(S_2\) 。记为操作 \(c\) 。 \(4:\) 如果栈 \(S_2\) 不为空,将 \(S_2\) 栈顶元素弹出至输出序列。记为操作 \(d\) 。 输出描述: 输出字典序最小的操作序列,如果不满足双栈排序性质,输出 \(0\) 。 思路: 写了半天单调栈+贪心+模拟被提醒是二分图。 写一篇题解纪念我逝去的三个小时。 首先有这样一个性质。 如果存在这种情况 \(i<j<k\) 且 \(a(k)<a(i)<a(j)\) ,那么 \(a(i),a(j)\) 不能处于同一个栈内,这是一个充分必要条件。 证明: 必要性:如果有 \(i<j<k\) 且 \(a(k)<a(i)<a(j)\) ,则因为 \(a(i)\) 和 \(a(j)\) 后面都存在一个更小的数 \(a(k)\) ,因此 \(a(i),a(j)\) 都不能从栈中被弹出

【笔记】【二分图】

拥有回忆 提交于 2019-12-02 06:45:59
二分图的验证 bfs染色法 二分图最大匹配 1)增广路有奇数条 2)起点终点都没有被遍历 3)奇数条边不在匹配中,偶数条边在匹配中 刷题的时候看到的 即得易见平凡,仿照上例显然。 留作习题答案略,读者自证不难。 反之亦然同理,结论自然成立。 略去过程QED,由上可知证毕。 来源: https://www.cnblogs.com/xwww666666/p/11735157.html