一般图最大匹配(带花树算法)

强烈推荐2015年集训队论文中陈胤伯的《浅谈图的匹配算法及其应用》,里面对匹配的性质及各类匹配算法都有很清晰的讲解。

以下的内容只是读完论文后我的一些体会。
求最大匹配的过程就是在求一条从未匹配点出发走到另一个未匹配点,并且路径是匹配边与非匹配边交替的简单路径。在二分图中,根据dfs/bfs的过程,我们可以画出一棵交错树,树中的边匹配边与非匹配边交替:
在这里插入图片描述
容易发现树中的白点都是被匹配边“拉入”树中的,我们只需要dfs白点的出边。

我们将交错树中的点分为1类点和2类点,其中根为1类点,每次我们枚举的是1类点的出边。

在二分图中只存在偶环,所以当一个点 u u u dfs到一个已经访问过的点 v v v 时, v v v必定是2类点,此时再次dfs v v v 显然并无意义。

但在一般图中,当一个点 u u u dfs到一个已经访问过的点 v v v 时, v v v可能是1类点,这就造成了环上的2类点的出边也可能出现在交错路中,如下图:
在这里插入图片描述
不难发现,沿匹配边进入 h h h可以到环上其他任意点沿非匹配边出去(顺时针,逆时针总有一种走法可行)

于是我们可以将这个奇环缩为一个点(非匹配边连成一朵花), h h h为花根。并将1类点的 p r e pre pre设为它在环上经过非匹配边到达的那个点。

截取论文中的最后一段:
在这里插入图片描述
论文中前面提到如果在某一次找不到从 x x x出发的增广路,增广多次以后仍然没有从 x x x出发的增广路,所以每个点只需要找一遍,总复杂度 O ( n ∗ ( n 2 + m ) ) = O ( n 3 ) O(n*(n^2+m))=O(n^3) O(n(n2+m))=O(n3)
PS:uoj79可以用随机化水过,事实上最大匹配问题似乎随机化的正确性表现的异常优秀

Code(uoj79):

#include<bits/stdc++.h>
#define maxn 505
#define maxm 250005
using namespace std;
int n,m;
int fir[maxn],nxt[maxm],to[maxm],tot;
inline void line(int x,int y){nxt[++tot]=fir[x],fir[x]=tot,to[tot]=y;}
int mat[maxn],typ[maxn],F[maxn],pre[maxn],q[maxn],ql,qr,vis[maxn],tim;
int find(int x){return !F[x]?x:F[x]=find(F[x]);}
int LCA(int u,int v){//O((u,v)在BFS树上的距离) 
	for(++tim;;swap(u,v)) if(u){
		if(vis[u=find(u)]==tim) return u;//点要对应到花根上
		vis[u]=tim,u=pre[mat[u]];//花根连出的环的两条边一定是非匹配边
	}
}
void blossom(int u,int v,int tp){
	while(find(u)!=tp){//缩花可能是几个小花并成一个大花,此时小花就没有必要存了,保留大花。
	//小花花根的pre需要指向从u走上来的点,所以这里不能令u=find(u)
		pre[u]=v,v=mat[u];
		if(typ[v]==2) typ[q[++qr]=v]=1;
		if(find(u)==u) F[u]=tp;
		if(find(v)==v) F[v]=tp;//前面的判断貌似可以不要?
		u=pre[v];
	}
}
bool aug(int s){
	for(int i=1;i<=n;i++) typ[i]=F[i]=pre[i]=0;
	typ[q[ql=qr=1]=s]=1;
	while(ql<=qr){
		int u=q[ql++];
		for(int i=fir[u],v;i;i=nxt[i])
			if(typ[v=to[i]]!=2&&find(u)!=find(v)){//找到的点要么没访问过,要么就是找到新的可以倒着走的环
				if(!typ[v]){
					typ[v]=2,pre[v]=u;
					if(mat[v]) typ[q[++qr]=mat[v]]=1;
					else{
						while(v) {int t=mat[pre[v]]; mat[mat[v]=pre[v]]=v,v=t;}
						return 1;
					}
				}
				else {int lca=LCA(u,v); blossom(u,v,lca),blossom(v,u,lca);}
			}
	}
	return 0;
}
int main()
{
	scanf("%d%d",&n,&m); int x,y;
	while(m--) scanf("%d%d",&x,&y),line(x,y),line(y,x);
	int ans=0;
	for(int i=1;i<=n;i++) if(!mat[i]) ans+=aug(i);
	printf("%d\n",ans);
	for(int i=1;i<=n;i++) printf("%d%c",mat[i],i==n?10:32);
}

UOJ的一个随机化的提交。
随机的时候注意点的顺序要 random_shuffle 不然会被卡。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python中可以使用递归函数和turtle模块来输出花树。turtle模块提供了简单的形绘制功能,递归函数可以根据规律和参数不断调用自身来实现树枝和树叶的绘制。 首先,我们需要导入turtle模块: ```python import turtle ``` 然后,设置绘窗口的大小和背景颜色: ```python window = turtle.Screen() window.setup(800, 600) window.bgcolor("white") ``` 接下来,定义一个递归函数draw_branch,该函数负责绘制树枝的功能。函数中包含一些参数,如树枝的长度、树枝的角度、和树枝的颜色: ```python def draw_branch(length, angle, color): if length < 10: return else: turtle.pencolor(color) turtle.forward(length) turtle.right(angle) draw_branch(length * 0.7, angle, color) turtle.left(angle * 2) draw_branch(length * 0.7, angle, color) turtle.right(angle) turtle.backward(length) ``` 然后,定义一个递归函数draw_flower,该函数负责绘制花朵的功能。函数中包含一些参数,如花朵的长度和花朵的颜色: ```python def draw_flower(length, color): if length < 10: return else: turtle.right(45) draw_branch(length, 25, color) draw_flower(length * 0.7, color) ``` 最后,在主程序中调用draw_flower函数,并提供一些参数来绘制花树: ```python draw_flower(100, "red") ``` 运行程序后,就可以在绘窗口中看到输出的花树了。 这只是一个简单的花树绘制示例,可以根据需要调整参数来实现更复杂的绘制效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值