(附一道例题)

Time Limit: 1000 ms   Memory Limit: 128 MB

Description

  最小点覆盖是指在二分图中,用最小的点集覆盖所有的边。当然,一个二分图的最小点覆盖可能有很多种。

  现在给定一个二分图,请你把图中的点分成三个集合:

  如果在任何一种最小点覆盖中都不包含这个点,则认为该点属于N集合。

  如果在任何一种最小点覆盖中都包含这个点,则认为该点属于A集合。

  如果一个点既不属于N集合,又不属于A集合,则认为该点属于E集合。

Input

  第一行包含三个整数n, m, k,分别表示二分图A侧点的数量,二分图B侧点的数量,边的数量。

  接下来k行,每行两个整数i, j,分别表示二分图A侧第i号点与二分图B侧第j号点有连边。

  数据保证无重边。

Output

  第一行输出一个长度为n的字符串,其中第i个字符表示二分图A侧第i个点所属的集合。

  第二行输出一个长度为m的字符串,其中第i个字符表示二分图B侧第i个点所属的集合。

Sample Input Sample Output

11 9 22
1 1
1 2
1 3
1 8
1 9
2 1
2 3
3 2
3 4
4 3
4 5
5 2
5 4
5 6
6 6
6 7
7 5
7 7
8 7
9 7
10 7
11 7

AEEEEEENNNN
EEEEEEANN

Hint

  对于10%的数据,$1 \leq n, m \leq 5$

  对于40%的数据,$1 \leq n, m \leq 100$

  对于100%的数据,$1 \leq n, m \leq 1000, 0 \leq k \leq n*m$

  


Konig定理

  ORZ贴上Matrix67的博http://www.matrix67.com/blog/archives/116ORZ,这里证明了Konig定理,那我按着他的思路再述说一次。(我从这里才看懂的)。

  以及一篇思路很清晰的博:http://www.renfei.org/blog/bipartite-matching.html,里面直观地讲述了Hungary的本质,但主要还是看交错轨和增广路的概念即可。

  Konig定理:最小点覆盖的点集合大小等于最大匹配数。

  其中提到了最小点覆盖是如何找出的:

    1.正常二分图匹配。

    2.从右部找到未被匹配的点,走交错轨(先未匹配边后有匹配边,反复交错),将交错轨经过的点打上标记;

    3.左部有标记的点和右部无标记的点构成了最小点覆盖集。

  弄明白原理,这道题就很容易了。

  ORZMatrix67,我们分三步证明:

  

  1.这样弄出的点总共只有m个:

    我们的出发点总是右部未匹配的点。由于现在的图是最大匹配,交错轨一定是从右部出发,在右部结束,也就是结束时的边一定是匹配边(否则就满足增广路的性质,这张图就不是最大匹配了,矛盾);从右往左走的一定是非匹配边,从左往右走的一定是匹配边

    贴张图(出于Matrix67的博)

    

    发现:每条匹配边的某一端都是一个最小点覆盖集中的点。Why?

    我们选择的点中:左半部分有标记的,那都是在走交错轨的时候通过匹配边从右往左走过来的,于是交错轨中经过的左部点与匹配边一一对应。

    右半部分无标记的,代表没有交错轨经过,那是因为我们开始走的时候选的是未匹配点作为起点,且途中从左往右走的是匹配边,二者都没有这一个点的份。因此?因此它们是匹配点,也就是与匹配边一一对应。

    得证这样选出的点总共只有m个。Get√

  2.这样弄出的m个点能覆盖全部边:

     先选出的交错轨已经覆盖了一定数量的边;那么为什么选择右边无标记的点就可以覆盖剩下的边?

     首先,交错轨中的边一定是两端都有标记的;不是两端都有标记的边不属于交错轨。

     其次,左边无标记而右边有标记的边是不存在的:如果这是一条匹配边,那么右边的标记只能是从左边走来的,那么左边也应有标记;如果这是一条非匹配边,那么一定能从右边走到左边,左边也应该有标记。

     那么,只剩下左无右无、左有右无两种边存在,发现右端都是“无”,那么我们选择右端未被标记的点,就可以覆盖剩下的全部边。

  

  3.这样弄出的最小覆盖集是最少的(这不废话吗):

     覆盖所有的匹配边就至少需要m个点,嗯还能再少吗......

  证毕。


题解

  根据上面提到的选点的方式,选的是左边有标记的点与右边无标记的点。

  出发时一定要选右部未匹配的点,也就是它们一定会打上标记。然而我们最终选的是右边无标记的点,所以右部未匹配的点一定不在最小覆盖集内---->N。

  左部未匹配的点,意味着交错轨从未经过,也就是它们一定没有标记。我们选择的是左边有标记的点,所以左部未匹配的点一定不在最小覆盖集内---->N。

  所以未匹配的点(暂且归为集合A)一定不在最小覆盖集中。

  既然A不在,那么与它们相连的点(归为集合B)就必须在--->A,不然就无法覆盖到它们之间相连的边了。

  那么B中的点,如果是匹配点,那么它的另一侧匹配点就不能在。当该点为左部点时,右边应该打上标记,不会被选;当该点为右部点的时候,它应该没有标记,属于选择的点的第二类点(右部无标记点),那么左边也就是另一侧匹配点就没必要选。

  

  重复上面判断步骤,判断出A和N的存在,剩下的就是E。这一步可以用类似广搜的操作完成。


 #include <cstdio>
#include <cstring>
#include <queue>
#define mp make_pair
using namespace std;
typedef pair<int,int> pii;
const int N=;
int n,m,k,use[N*],from[N*],h[N*],tot,col[N*];
struct Edge{int v,next;}g[N*N*];
queue<pii> q;
inline void addEdge(int u,int v){
g[++tot].v=v; g[tot].next=h[u]; h[u]=tot;
}
bool Hungary(int u){
for(int i=h[u],v;i;i=g[i].next){
if(!use[v=g[i].v]){
use[v]=;
if(!from[v]||Hungary(from[v])){
from[v]=u;
return true;
}
}
}
return false;
}
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=,u,v;i<=k;i++){
scanf("%d%d",&u,&v);
addEdge(u,v+n); addEdge(v+n,u);
}
for(int i=;i<=n;i++){
memset(use,,sizeof use);
Hungary(i);
}
for(int i=;i<=m;i++)
if(from[n+i])
from[from[n+i]]=n+i;
for(int i=;i<=n+m;i++)
if(!from[i]&&!col[i]){
col[i]=;
q.push(mp(i,));
}
int u,f;
pii s;
while(!q.empty()){
s=q.front(); q.pop();
u=s.first; f=s.second;
for(int i=h[u],v;i;i=g[i].next)
if(!col[v=g[i].v]&&(col[u]==)||(col[u]==&&v==from[u])){
col[v]=f;
q.push(mp(v,f==?:));
}
}
for(int i=;i<=n;i++)
if(col[i]==) putchar('N');
else if(col[i]==) putchar('A');
else putchar('E');
puts("");
for(int i=n+;i<=n+m;i++)
if(col[i]==) putchar('N');
else if(col[i]==) putchar('A');
else putchar('E');
puts("");
return ;
}

奇妙代码

【Learning】最小点覆盖(二分图匹配) 与Konig定理证明的更多相关文章

  1. 二分图最小覆盖的Konig定理及其证明,最小的覆盖证明

    [转http://www.cppblog.com/abilitytao/archive/2009/09/02/95147.html  ->  http://yejingx.ycool.com/p ...

  2. 【CF981F】Round Marriage(二分答案,二分图匹配,Hall定理)

    [CF981F]Round Marriage(二分答案,二分图匹配,Hall定理) 题面 CF 洛谷 题解 很明显需要二分. 二分之后考虑如果判定是否存在完备匹配,考虑\(Hall\)定理. 那么如果 ...

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

    题意: 给定一个H行W列的矩阵,在矩阵的格点上放带权值的卡片(一个点上能放多张). 现在从每行每列各拿走一张卡片(没有可以不拿),求可以拿到的最大权值. 卡片数N<=1e5,H,W<=1e ...

  4. POJ 3041 Asteroids 最小点覆盖 == 二分图的最大匹配

    Description Bessie wants to navigate her spaceship through a dangerous asteroid field in the shape o ...

  5. POJ 3041 Asteroids(二分图 && 匈牙利算法 && 最小点覆盖)

    嗯... 题目链接:http://poj.org/problem?id=3041 这道题的思想比较奇特: 把x坐标.y坐标分别看成是二分图两边的点,如果(x,y)上有行星,则将(x,y)之间连一条边, ...

  6. 牛客 216D 消消乐 (二分图最小点覆盖)

    大意: 给定棋盘, 每次消除一行或一列, 求最小次数使得消除完所有'*'. 裸的二分图最小点覆盖. 二分图的最小点覆盖等于最大匹配, 输出方案时从所有左部未盖点开始标记交替路上的点, 最后左部所有未标 ...

  7. 【最小点覆盖】POJ3041-Asteroids

    [题目大意] 在n*n的网格上有n个点,每次删除一行或者一列,问至少要删除几次才能删除完全部的这些店? [思路] 在国庆最后一天到来前,把二分图的三个基本情况[最小点覆盖][DAG图的最小路径覆盖]和 ...

  8. UVA 11419 SAM I AM(最大二分匹配&最小点覆盖:König定理)

    题意:在方格图上打小怪,每次可以清除一整行或一整列的小怪,问最少的步数是多少,又应该在哪些位置操作(对输出顺序没有要求). 分析:最小覆盖问题 这是一种在方格图上建立的模型:令S集表示“行”,T集表示 ...

  9. 二分图最小点覆盖构造方案+König定理证明

    前言 博主很笨 ,如有纰漏,欢迎在评论区指出讨论. 二分图的最大匹配使用 \(Dinic\) 算法进行实现,时间复杂度为 \(O(n\sqrt{e})\),其中, \(n\)为二分图中左部点的数量, ...

随机推荐

  1. 2.CLI标准

    CLI  简称(CLI标准) 通用语言架构    维基百科地址: http://zh.wikipedia.org/wiki/通用语言架构 是一个开放的  技术规范  .它是由  微软  联合  惠普  ...

  2. hibernate解读之session--基于最新稳定版5.2.12

    前言 hibernate是一个实现了JPA标准的,用于对象持久化的orm框架.博主近一年开发都在使用. 前段时间在工作中遇到了一个hibernate的问题,从数据库查找得到对象后,修改了其中部分字段值 ...

  3. awk -f program.file 功能使用

    一.awk -f program.file 功能使用 一直没有使用过awk的-f功能,感觉鸡肋,不是很实用,更多的是因为没有需求的原因 下面介绍下awk -f的使用方法 awk可以指定默认的文件路径, ...

  4. 【转】shell学习笔记(四)——条件测试

    1 test 条件检测 当我要检测系统上面某些文件或者是相关的属性时,利用 test 这个命令来工作真是好用得不得了, 举例来说,我要检查 /home/oracle/zy是否存在时,使用: test ...

  5. 二级缓存:EHCache的使用

    EHCache的使用 在开发高并发量,高性能的网站应用系统时,缓存Cache起到了非常重要的作用.本文主要介绍EHCache的使用,以及使用EHCache的实践经验. 笔者使用过多种基于Java的开源 ...

  6. CSS——选择器2

    1.子选择器 (1).用于指定标签元素的第一代子元素,使用">"号. (2).例子: <style type="text/css"> .foo ...

  7. css层叠样式初学

    一.css简介 1.层叠样式表:叠加效果,不同css对同一html修饰,冲突部分,优先级高作用,不冲突部分,共同作用 2.css作用 (1)修饰html (2)替代了标签自身的颜色,字号等属性,提高复 ...

  8. 01_Python入门

    Python介绍 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆(中文名字:龟叔)为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程 ...

  9. configparser模块的常见用法

    configparser模块用于生成与windows.ini文件类似格式的配置文件,可以包含一节或多节(section),每个节可以有一个或多个参数(键=值) 在学习这个模块之前,先来看一个经常见到的 ...

  10. python3中time模块的用法及说明

    python中,导入time模块使用的命令是 import time 可以使用以下命令查看time模块内置的能够使用的方法: dir(time) 可以使用以下命令查看time模块中每个内置方法的说明: ...