【二分图】【找最大流、最小独立集、匈牙利算法】

匈牙利算法

http://blog.chinaunix.net/uid-20761674-id-74944.html


可以解决的图的问题:(二分图)
1.图的最小点覆盖数 = 图的最大匹配数;
2.图的最大点独立集 = 图顶点数 - 图的最大匹配数;
3.图的最小路径覆盖数 = 原图的顶点数 - 原图拆点后形成的二部图的最大匹配数;


二分图的定义:把顶点分成X和Y两个集合,每一条边的两个端点都分别在这两个集合里。

二分图的基本问题就是最大匹配了:在二分图中找一个边集,使得该边集所包含的边数最多。

基本算法是匈牙利算法,用DFS找增广路径,在此不多说了,详见: http://imlazy.ycool.com/post.1603708.html(写得十分透彻)

二分图之所以灵活,是因为有很多看似无关的问题都能转化到最大匹配的问题上来。


问题一:最小覆盖

寻找一个点集,使得图中每一条边至少有一个点在该点集中,且该点集所包含的点数最少。(最小覆盖的情况下,每边条有且仅有一个端点在该点集中)。

定理:二分图最小覆盖等于二分图的最大匹配。

证明:设最大匹配数为m。

1:至少要m个点

证:因为二分图的最大匹配数为m,而每条边的端点互不相同,故至少要有m个点,才可以覆盖到所有的边。

2:最多要m个点

证:若存在m+1个点,则必有一条边的两个端点在该点集中,删去其中一点仍可以保持每条边被覆盖到,以此类推,大于m个点的点集都不是最小覆盖。

综上:最小覆盖的点集所包含的点数等于m,即二分图的最小覆盖等于二分图的最大匹配。

经典问题

PKU3041 Asteroids,给定一个矩阵,矩阵上有若干个障碍物,你可以一次清除一行或者一列的障碍物,问最少的清除操作需要几步。

建图时,以障碍物为边,行为X集合,列为Y集合建立二分图,若在map[i][j]上有一个障碍物,则将第i行与第j列之间连上一条边。问题就转化成了最小覆盖问题,最小覆盖=最大匹配。

该题的变型是PKU2260 Muddy Fields,一张图上有若干的泥点,现在要用单位宽度的木板(长度不限)盖住这些泥点,且不能盖住干净的点。同样是以泥点为边,但这个时候不是单纯的一 行或者一列为一个集合了,而是以行上的连通块为X集合,列上的连通块为Y集合,如果连通块i和j相交,则将i与j之间连一条边。同样是最小覆盖=最大匹 配。

推荐题:PKU1325


问题二:最小路径覆盖

用最少的不相交简单路径覆盖所有的有向无环图上所有的顶点

定理:最小路径覆盖数=结点数-最大匹配数

证明:对于每条路径上的顶点,除了最后一个以外都有它的后继,则所需要的路径数就是没有后继的结点个数,对于n个结 点,我们把集合X和Y分别放入这n个结点,若i的后继是j,则i与j之间连一条边,又因为路径之间不相交,则每个结点都有惟一的后继,要使没有后继的结点 个数最少,则要求有后继的结点个数最多,即满足最大匹配。故最小路径覆盖数=结点数-最大匹配数。

经典问题

PKU1422 Air Raid,一张图上若干个点之间有单向边,且不存在环,现在你可以任意安排伞兵降落到几个点上,然后让他们遍历所有的点,要求不能有两个或以上的伞兵访问同一个点。

题目和最小路径覆盖的描述完全一样。最小路径覆盖数=结点数-最大匹配数。

该题的变型是PKU2594 Treasure Exploration,题目很相似,唯一不同的是没有了最后一句的限制,即一个点可以被多个人访问。

我一开始以为没了这个限制就要用别的方法来做了,但用搜索又想不好怎么标记,后来看了discuss,惊奇地发现 tq师兄和gsy师姐的留言,锁定到一个关键词:传递闭包。然后就做了一次floyd,再按照最小路径覆盖便过了,对于这个算法我的理解是:当某些相交的 点被匹配了以后,由于做过了传递闭包,其他的路径上的点就可以跳过相交点而直接与下一点匹配,这样就符合了题意。


问题三:最大独立集

找一个点集,其中任意两点在图中无边,且该点集包含的点的个数最多

定理:二分图最大独立集=结点数-最优匹配(一般图的最大独立集是NP完全问题)

证明:易知最大独立集的补集必定覆盖了所有的边,为使最大独立集包含的点的个数最多,我们要求的补集就成了最小覆盖,二分图的最小覆盖=最大匹配。故二分图的最大独立集=结点数-最大匹配。

经典问题

PKU1466 girls and boys,给出每个人与哪些异性有关系,求一个最大集合,其中的人都没有关系。

建图时把一个人拆成两个,分别放在X和Y集合里,这样求出的最大匹配/2就是实际的最大匹配数,避免了区分男的和女的后再放到两个集合里去。


//c语言实现的匈牙利算法
#include

#include
#define MAX 102
 
long n,n1,match;
long adjl[MAX][MAX];
long mat[MAX];
bool used[MAX];
 
FILE *fi,*fo;
 
void readfile()
{
fi=fopen("flyer.in","r");
fo=fopen("flyer.out","w");
fscanf(fi,"%ld%ld",&n,&n1);
long a,b;
while (fscanf(fi,"%ld%ld",&a,&b)!=EOF)
adjl[a][ ++adjl[a][0] ]=b;
match=0;
}
 
bool crosspath(long k)
{
for (long i=1;i<=adjl[k][0];i++)
{
long j=adjl[k][i];
if (!used[j])
{
used[j]=true;
if (mat[j]==0 || crosspath(mat[j]))
{
mat[j]=k;
return true;
}
}
}
return false;
}
 
void hungary()
{
for (long i=1;i<=n1;i++)
{
if (crosspath(i))
match++;
memset(used,0,sizeof(used));
}
}
 
void print()
{
fprintf(fo,"%ld",match);
fclose(fi);
fclose(fo);
}
 
int main()
{
readfile();
hungary();
print();
return 0;
}


poj3041 Asteroids  2010-01-05 15:54:06
 

                                   Asteroids
 
Bessie wants to navigate her spaceship through a dangerous asteroid field in the shape of an N x N grid (1 <= N <= 500). The grid contains K asteroids (1 <= K <= 10,000), which are conveniently located at the lattice points of the grid. 

Fortunately, Bessie has a powerful weapon that can vaporize all the asteroids in any given row or column of the grid with a single shot.This weapon is quite expensive, so she wishes to use it sparingly.Given the location of all the asteroids in the field, find the minimum number of shots Bessie needs to fire to eliminate all of the asteroids.

Input

* Line 1: Two integers N and K, separated by a single space. 
* Lines 2..K+1: Each line contains two space-separated integers R and C (1 <= R, C <= N) denoting the row and column coordinates of an asteroid, respectively.

Output

* Line 1: The integer representing the minimum number of times Bessie must shoot.

Sample Input

3 4
1 1
1 3
2 2
3 2

Sample Output

2

Hint

INPUT DETAILS: 
The following diagram represents the data, where "X" is an asteroid and "." is empty space: 
X.X 
.X. 
.X.
 

OUTPUT DETAILS: 
Bessie may fire across row 1 to destroy the asteroids at (1,1) and (1,3), and then she may fire down column 2 to destroy the asteroids at (2,2) and (3,2).

题意可以概括为:
给一个map,上面的X代表需要覆盖的位置,每次只能覆盖一行或一列,问最少需要执行几次覆盖操作。

二分图之所以灵活,是因为有很多看似无关的问题都能转化到最大匹配的问题上来。

问题一:最小覆盖,寻找一个点集,使得图中每一条边至少有一个点在该点集中,且该点集所包含的点数最少。(最小覆盖的情况下,每边条有且仅有一个端点在该点集中)。

定理:二分图最小覆盖等于二分图的最大匹配。

证明:设最大匹配数为m。

1:至少要m个点

证:因为二分图的最大匹配数为m,而每条边的端点互不相同,故至少要有m个点,才可以覆盖到所有的边。

2:最多要m个点

证:若存在m+1个点,则必有一条边的两个端点在该点集中,删去其中一点仍可以保持每条边被覆盖到,以此类推,大于m个点的点集都不是最小覆盖。

综上:最小覆盖的点集所包含的点数等于m,即二分图的最小覆盖等于二分图的最大匹配。

经典问题:PKU3041 Asteroids,给定一个矩阵,矩阵上有若干个障碍物,你可以一次清除一行或者一列的障碍物,问最少的清除操作需要几步。


你可能感兴趣的:(图论)