码迷,mamicode.com
首页 > 其他好文 > 详细

最短路思想实现一般图最大匹配

时间:2016-05-18 21:46:44      阅读:139      评论:0      收藏:0      [点我收藏+]

标签:

考虑一下一般图和二分图的区别,无非就在于二分图可能出现长为奇数的环。

如何排除奇数环的影响???

 

最短路

 

设一般图中每条可匹配边长为1,该次匹配起点为v。

根据最短路定理,我们可以知道,v在带花树上到任意一个终点(即未匹配的点)的最短距离一定为奇数,且路径上一定不存在环。

那么,用广搜的方法去贪最短路的时候,贪出来的第一条路(即最短路)一定不含环。

设[1,n]代表S型点,[n+1,2*n]代表T型点,dist[i]表示v到i的最短路上经过的点数。

设ance[i][j]表示i的dist值为j的祖先的原编号,hash[i][j]表示j(原编号)是否是i的祖先。

那么i能拓展出j的充要条件就是(dist[i]+1<dist[j]&&!hash[i][j])

即满足最短路且满足非祖先关系。

通过广搜实现这个特殊图的最短路,从而得到一般图最大匹配。

代码如下,带上注释比我从网上找到的最短的带花树(不带注释)要短200字节

#include<cstdio>//O(n^3),神板子,码量不大 
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;

const int maxl=99999999;
const int maxn=510; 
int n,m,i,j,s,v,match[maxn],ance[maxn*2][maxn],dist[maxn*2],ans;
//[1,n]代表S型点,[n+1,2*n]代表T型点
//ance[i][j]表示i的dist为j的祖先的原编号,hash[i][j]表示j(原编号)是否是i的祖先 
vector <int> l[maxn];
bool hash[maxn*2][maxn];

int z[maxn*2],r;
void change(int x){
	ans++;
	for (int i=dist[x];i>0;i-=2){
		match[ance[x][i]]=ance[x][i-1];
		match[ance[x][i-1]]=ance[x][i];
	}
}
void extend(int x){
	int i,j,k,v=(x>n?x-n:x);
	if (x>n){//若为T型点 
		if (match[v]==0){//发现单身,增广 
			change(x);return;
		}
		k=match[v];
		if (!hash[x][k]&&dist[k]>dist[x]+1){//十分类似于dijsktra的松弛操作 
			dist[k]=dist[x]+1;
			for (j=1;j<=dist[x];j++)
				hash[k][ance[k][j]=ance[x][j]]=1;
			hash[k][ance[k][dist[k]]=k]=1;
			z[++r]=k;
		}
	}
	else
	for (i=0;i<(int)l[v].size();i++){//十分类似于dijsktra的松弛操作 
		k=n+l[v][i];
		if (!hash[x][l[v][i]]&&dist[k]>dist[x]+1){
			dist[k]=dist[x]+1;
			for (j=1;j<=dist[x];j++)
				hash[k][ance[k][j]=ance[x][j]]=1;
			hash[k][ance[k][dist[k]]=l[v][i]]=1;
			z[++r]=k;
		} 
	}
}
void bfs(int x){
	z[r=1]=x;						//初始化 
	memset(ance,0,sizeof ance);
	memset(hash,0,sizeof hash);
	for (int i=1;i<=2*n;i++) dist[i]=maxl;
	dist[x]=hash[x][x]=1;
	ance[x][1]=x;
	for (int i=1;i<=r;i++){			//广搜 
		extend(z[i]);
		if (match[x]!=0) return; 
	}
}

int main()
{
	scanf("%d%d",&n,&m);
	for (i=1;i<=m;i++){
		scanf("%d%d",&s,&v);
		l[s].push_back(v);
		l[v].push_back(s);
	}
	for (i=1;i<=n;i++)
	if (match[i]==0)
		bfs(i);
	printf("%d\n",ans);
	for (i=1;i<=n;i++) printf("%d ",match[i]);
	putchar(‘\n‘);
	return 0;
}

 

最短路思想实现一般图最大匹配

标签:

原文地址:http://www.cnblogs.com/FoolMike/p/5503387.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!