基本概念
二分图:二分图指的是这样的一种图,其所有顶点可以分成两个集合X和Y,其中X或Y中任意两个在同一个集合中的点都不相连,所有边关联在两个顶点集中。
匹配:匹配是图边集的一个子集,满足任意两条边都不依附于同一个顶点
最大匹配:边数最多的匹配
饱和顶点:与匹配中的边相关联的顶点
M交错路:M是图的一个匹配,边在M和M的补集中交替出现的路叫M交错路
M增广路:起点和终点都是非饱和点的M交错路
算法原理
定理:一个匹配是最大匹配的充要条件是不存在增广路
匈牙利算法就是通过不断找增广路来增大匹配
几个重要结论
最小点覆盖:选最少的点使得每条边都至少和其中一个点关联。
最小点覆盖=最大匹配
最小边覆盖:选最少的边使得每个点都和所选边关联
最小边覆盖=顶点数-最大匹配
最小路径覆盖:用尽量少的不相交的简单路径覆盖有向无环图G的所有结点。
建立二分图G‘如下:
把所有顶点i拆成两个:X结点集中的i和Y结点集中的i’,如果有边i->j,则在二分图中连边i->j’。最小路径覆盖=G中的顶点数-G’的最大匹配.
如果题目可以用相交的简单路径去覆盖的话,需要用floyed算法去传递闭包,这样就有新的路径可以绕开交点,将模型转化成了用不相交的路径去覆盖了。比如poj2594
二分图最大独立集:在有N个点的图中选出m个点,使着m个点两两之间没有边,求m的最大值。
如果是二分图,那么最大独立集=N-最大匹配
模板
const int maxn=1600;
int from[maxn],vis[maxn];
int n;
vector<int> g[maxn];
bool Find(int u)
{
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(!vis[v])
{
vis[v]=1;
if(from[v]==-1 || Find(from[v]))
{
from[v]=u;
return true;
}
}
}
return false;
}
void solve()
{
int ans=0;
memset(from,-1,sizeof(from));
for(int i=0;i<n;i++)
{
memset(vis,0,sizeof(vis));
if(Find(i)) ans++;
}
printf("%d\n",ans);
}