二分图和网络流
二分图
如果一张图的n个节点能分成两部分,使每个部分的点之间没有连边,这个图就是二分图。
二分图的判断
定理:一张无向图是二分图,当且仅当图中不存在奇环。
简单证明:如果一张图里不存在环,可以将节点沿着链以左右交替的顺序放入左右两部分,此时图明显是一个二分图。如果一张图存在环,也可以从任意一节点开始将节点沿环放入左右部分,但是起始点和最终点应该属于不同部分,不然当连接起始点和最终点的时候就会产生同一个部分中的连边,不符合二分图定义。显然,当环的长度奇数时起始点最终点一定在同一部分,而偶环没关系。
二分匹配
从婚配问题开始解释二分匹配
过山车
有n个女生和m个男生,每个女生会允许特定几个男生和她坐过山车。只有男女配对的人才能上过山车,请问最多能上去几对?
简单的开始讲,如果2男2女,a女能选择a男和b男,b女只能选择a男,那么a女应该和b男配对,不然就至少无法达到最大配对数了。
二分图的增广路
一眼看出来a女要和b男配对,你当然做得到,但是要怎么用算法描述这个问题,要引入一个概念,叫增广路。
从一个未匹配点开始,如果能依次沿着已匹配边,未匹配边交替,最后能走到另一部分的一个未匹配的点,这条路就叫做增广路。
增广路的作用:当你把增广路上的边的是否匹配全部取反,能得到比原来匹配数更大的合法匹配方案。
由增广路直接产生的匈牙利算法在此不多介绍,贴个板子就撤
实际上我不再用这个板子了,因为有一次它超时了,然后我发现dinic又快又方便
这个板子可以用前向星优化到O(n+m),但是有了dinic谁还去优化一个古老的板子呢?
//匈牙利算法求最大二分匹配,适用于稠密图,稀疏图直接转隔壁dinic
//本质是个贪心算法
//最大二分匹配的方法不唯一,但是最大二分匹配的个数是唯一的
#define MAXN 100000
bool used[MAXN]; //用过了为1
bool edge[MAXN][MAXN]; //左边的在左括号,这是一个邻接矩阵
bool select[MAXN]; //配对关系
bool Ed(int x,int m){//右边人数
for(int i=1;i<=m;i++){
if(edge[x][i]&&!used[i]){
used[i]= true;//used每次调用都要置零,如果调用某个数不成功,那么后面的所有数据调用这个数据也不会成功
if(select[i]==0||Ed(select[i],m)){//没有配对或者之前与ta配对的找得到其他配对
select[i]=x;
return true;
}
}
}
return false;
}
int Edmonds(int n,int m){//左边的人数,右边的人数
int c=0;
for(int i=1;i<=n;i++){ //遍历左边的每个人
memset(used,0, sizeof(used));
if(Ed(i,m)) c++; //如果找得到增广路配对就++
}
return c;
}
网络流
用定义解释这个东西相当晦涩,举个栗子
自来水厂源源不断地生产着自来水往你家送,但是由于你家离自来水厂实在是太远了,所以有n个中继站,中继站之间有m条连水管,因为科技能力和经费有限,每个水管的运送能力都不是无限的。
我们知道,中继站不会生产水,上一个中继站给下一个中继站送的水受到水管的限制。
虽然水厂的水是无限的,但是由于容量原因每一个中继站的水都不是无限的,怎么将有限的水分配到不同的水管,使得最后到你家的水的总量最大,这就是网络流问题。
由此可以看出网络流的两个性质:容量限制,流量守恒。不解释了。
同时看图我们可以知道,最大流的分配方式是不唯一的,但是分配结果是唯一的,就是到你家的水可以经过不同的管子,但始终有这么多。
一个网络是一张有向图,,另有两个特殊点,称为源点S和汇点T。对于每一条边(x,y),有一个容量c(x,y)和一个流量f(x,y),要求满足
1.f(x,y) ≤ c(x,y)
2.f(x,y)=-f(y,x)
3. ∀ \forall ∀x ≠ \ne =S, ∀ \forall ∀y ≠ \ne