二分图的最小覆盖 = 最大匹配
这是为什么呢? 让我们来分析一下, 这里有一个很好的模拟过程: 将右边未匹配上的点依次加标记, 然后标记 左边与右边标记的相连的点 ,左边的点一定是最大匹配上的点,不然找到的一定不是最大匹配, 标记最大匹配且左边已经标记了的点 。 最后 取左边标记了的点 和右边未标记的点就组成了最小覆盖。 现在最大匹配的点一定都覆盖了,左边是最大匹配,右边不是的边也覆盖了, 右边是最大匹配,左边不是这种情况也覆盖了。所有情况都覆盖了 , 而左边标记了的点 由最大匹配对应的右边的点 与右边未标记的(为标记一定是最大匹配上的) 加起来就是最大匹配数。
图的独立集:寻找一个点集,其中任意两点在图中无对应边。
二分图的最大独立集 = 图的点数 - 最大匹配数
这个比较好理解, 把最小覆盖的点去了,则图中一条边也没有了。剩下的就是最大独立集。
最小路径覆盖问题:用尽量少的不相交简单路径覆盖有向无环图的所有顶点。
将每个顶点分为两个,分别在X集合和Y集合中,如果存在有向边(a,b),对应在二分图中有(Xa,Yb)
最小路径数 = 节点数 - 最大匹配
参考 http://hi.baidu.com/desmoon/blog/item/ce5de032bc6d63f11a4cff16.html
对于任意图:
|最小边覆盖|+|最大匹配|=|V|
二分图的最大匹配=最小点覆盖数
对于二分图:
以下数值等价.
最大匹配
最小点覆盖
|V|-最大独立集(二分图or有向无环图)
|V|-最小边覆盖数
|V|-最小路径覆盖数(有向无环图)
|V|-最小路径覆盖数/2(无向图)
(上面括号里有有向无环图的,均是将一个点拆成两个点连边匹配)
由于任意图的那几个几乎用不到于是这里只贴二分图的定义
最小点覆盖:理解为点覆盖边,即用最小的点覆盖所有的边。(若一条边的其中一个端点被选用,这条边就被覆盖了)
最大独立集:求一个最大的点集,里面的点不存在任何的边相连。
最小边覆盖:理解为边覆盖点,用最少的边把图中的点全部覆盖。
最小路径覆盖:用最少的路径把图中的所有点覆盖。
另外:最大独立集与最小覆盖集互补。
推广到有权的形式也一样,即最大点权独立集与最小点权覆盖集互补
求最小点权覆盖集可以这样求:
先对图黑白染色,然后向白色的点放X部,黑色的点放Y部。
1、连边[S,i],容量等于i的点权。(对于二分图的X集)
2、连边[i,T],容量等于i的点权。(对于二分图的Y集)
3、对于有边的i和j连边[i,j](i∈X,j∈Y),容量为INF
最后得出的最大流就是最小点权覆盖,实际上是最小割与之对应。
对于有向无环图:
最大反链=|V|-最大匹配
http://hi.baidu.com/edwardmj/blog/item/b5fc0419bd3661f1af513325.html
#include<stdio.h>
#include<string.h>
int map[505][505];
int used[505],n;
int link[505];
int findPath(int p)
{
for(int i=1;i<=n;i++)
{
if(!used[i] && map[p][i])
{
used[i]=1;
if(!link[i] || findPath(link[i]))
{
link[i]=p;
return 1;
}
}
}
return 0;
}
int hungary()
{
int ans=0,i;
for(i=1;i<=n;i++)
{
memset(used,0,sizeof(used));
if(findPath(i)) ans++;
}
return ans;
}
int main()
{
int k,i,u,v;
memset(link,0,sizeof(link));
scanf("%d%d",&n,&k);
for(i=0;i<k;i++)
{
scanf("%d%d",&u,&v);
map[u][v]=1;
}
printf("%d\n",hungary());
return 0;
}