二分图:
一种特殊的无向图,可以分为两个有关联边的集合(同一个集合内的点之间的点没有边)如图:
谈到二分图,不得不将二分图的匹配(最大匹配,最小没啥意义)
这就要谈到关于匈牙利算法,它也许不是最优化的,但是它是把这一类题目最基本思想展现出来的最简单最直接的算法。
其实这类似于贪心的过程:
我们如果如果有可以相互匹配的可以直接匹配,有不能匹配的点B递归地寻找那些理论上可以匹配但已经匹配的点A,尝试修改和A匹配的点的匹配,使B点尽可能地去实现匹配。
第一个蓝色点可以匹配:直接匹配
第二个蓝色点可以匹配:直接匹配
第三个蓝点不能匹配:寻找第二个红色点,观察它的匹配点能否修改。
第二个红色点的匹配点——第二个蓝色点不能直接匹配其他点(除了第二个红色点),去寻找另一个点(第一个红点)
发现第一个红点对于第一个蓝点可以匹配到第三个红点,以上的递归过程都可以实现。
(如果最后发现都不能匹配,那么之前递归的尝试修改的过程全都无效,回到第二个点匹配之后,且第三个点不能匹配。)
最后一个点直接匹配
主要代码:(其余部分按照题意编写)
const int maxn = 5e5+10;
int head[maxn],cnt = 0,be[maxn];
bool Vis[maxn];
struct Edge{//链式向前星,初始化head为-1。
int to,next;
}edge[maxn];
void add_edge(int x,int y){
edge[cnt]={y,head[x]};
head[x] = cnt++;
}
bool dfs(int u){//每进行一个点的匹配是,要把Vis归0,保证所有点都可以尝试修改一次。
for(int i = head[u];i >=0;i = edge[i].next)
{
int v = edge[i].to;
if(!Vis[v]){
Vis[v] = 1;
if(!be[v]||dfs(be[v])){//没有匹配直接匹配,匹配了的,尝试修改匹配关系
be[v] = u;
return 1;
}
}
}
return 0;
}