[gotoac]二分图最大匹配hungary & 二分图最佳完美匹配KM(邻接表&邻接矩阵) beta1

struct hungary{
	int n,m;            //X集和Y集的点数
	int match[M];       //匹配
	bool vis[M];        //是否在增广路上
	vector<int>g[M];    //邻接表
	void init(int _n,int _m){
		n=_n,m=_m,clr(match,-1,m);
		for(int i=0;i<n;i++) g[i].clear();
	}
	void insert(int u,int v){g[u].push_back(v);}
	bool augment(int u){//增广
		for(int i=0,v;i<g[u].size();i++){
			if(!vis[v=g[u][i]]){
				vis[v]=1;
				if(match[v]==-1 || augment(match[v])){
					match[v]=u;
					return true;
				}
			}
		}
		return false;
	}
	int maxMatch(){
		int res=0;
		for(int i=0;i<n;i++){
			clr(vis,0,m);
			if(augment(i)) res++;
		}
		return res;
	}
};


struct KM{//邻接表
	typedef int type;
	struct edge{
		int from,to;
		type w;
		edge(int u,int v,type _w){from=u,to=v,w=_w;}
	};
	int n,m;            // X/Y集的点数
	int match[M];       // 匹配
	type lx[M],ly[M],d; // X/Y项标,松弛量
	bool vx[M],vy[M];   // X/Y集的点是否在已经访问
	vector<edge>edg;    // 边表
	vector<int>g[M];    // 邻接表
	void init(int _n,int _m){
		n=_n,m=_m;
		clr(match,-1,m),edg.clear();
		for(int i=0;i<n;i++) g[i].clear();
	}
	void insert(int u,int v,type w){
		edg.push_back(edge(u,v,w));
		g[u].push_back(edg.size()-1);
	}
	bool augment(int u){// 增广
		vx[u]=1;
		for(int i=0;i<g[u].size();i++){
			edge& e=edg[g[u][i]];
			if(vy[e.to]) continue;
			if(lx[u]+ly[e.to]==e.w){
				vy[e.to]=1;
				if(match[e.to]==-1 || augment(match[e.to])){
					match[e.to]=u;
					return true;
				}
			}else getmin(d,lx[u]+ly[e.to]-e.w);
		}
		return false;
	}
	type maxWeight(){
		int i,j;
		for(i=0;i<m;i++) ly[i]=0;
		for(i=0;i<n;i++){
			lx[i]=-INF;
			for(j=0;j<g[i].size();j++)
				getmax(lx[i],edg[g[i][j]].w);
		}
		for(i=0;i<n;i++){
			for(;;){
				clr(vx,0,n),clr(vy,0,m);
				d=-1;
				if(augment(i)) break;
				for(j=0;j<n;j++) if(vx[j]) lx[j]-=d;
				for(j=0;j<m;j++) if(vy[j]) ly[j]+=d;
			}
		}
		type res=0;
		for(i=0;i<n;i++) res+=lx[i];
		for(i=0;i<m;i++) res+=ly[i];
		return res;
	}
};

struct KM{//邻接矩阵
	typedef int type;
	int n,m,match[M];          // X/Y集的点数,匹配
	type lx[M],ly[M],w[M][M],d;// X/Y项标,松弛量
	bool vx[M],vy[M];          // X/Y集的点是否在已经访问
	void init(int _n,int _m){
		n=_n,m=_m,clr(match,-1,m);
		for(int i=0;i<n;i++) for(int j=0;j<m;j++) w[i][j]=-INF;
	}
	bool augment(int u){//增广
		vx[u]=1;
		for(int v=0;v<m;v++){
			if(vy[v]) continue;
			if(lx[u]+ly[v]==w[u][v]){
				vy[v]=1;
				if(match[v]==-1 || augment(match[v])){
					match[v]=u;
					return true;
				}
			}else getmin(d,lx[u]+ly[v]-w[u][v]);
		}
		return false;
	}
	type maxWeight(){
		int i,j;
		for(i=0;i<m;i++) ly[i]=0;
		for(i=0;i<n;i++){
			lx[i]=-INF;
			for(j=0;j<m;j++)
				getmax(lx[i],w[i][j]);
		}
		for(i=0;i<n;i++){
			for(;;){
				clr(vx,0,n),clr(vy,0,m);
				d=-1;
				if(augment(i)) break;
				for(j=0;j<n;j++) if(vx[j]) lx[j]-=d;
				for(j=0;j<m;j++) if(vy[j]) ly[j]+=d;
			}
		}
		type res=0;
		for(i=0;i<n;i++) res+=lx[i];
		for(i=0;i<m;i++) res+=ly[i];
		return res;
	}
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值