带权的二分匹配

#include <queue>
#include <algorithm>
/*********************************************************/
//这些都是KM模板
const int N = 305;//二分图中每一个子图的点的最大数
const int INF = 1<<28;//正无穷

bool xckd[N], yckd[N];//在一次DFS中,Xi与Yi是否在交错树上
int  n;//点的个案
int edge[N][N];//二维权值信息用矩阵来存储
int xmate[N], ymate[N];//保存匹配结果
int lx[N], ly[N];//Xi与Yi和标号,即解说中的A[]和B[]
int slack[N];//松弛量
int prev[N];//?
queue<int> Q;

bool bfs();//寻找增广路径
void agument(int);
int KMMatch();//KM算法
/*********************************************************/
bool bfs()
{
	while(!Q.empty())
	{
		int p = Q.front(), u = p>>1;
		Q.pop();
		if(p&1)
		{
			if(ymate[u] == -1)
			{
				agument(u);
				return true;
			}
			else
			{
				xckd[ymate[u]] = true;
				Q.push(ymate[u]<<1);
			}
		}
		else
		{
			for(int i = 0; i < n; i++)
			{
				if(yckd[i])continue;
				else if(lx[u] + ly[i] != edge[u][i])
				{
					int ex = lx[u] + ly[i] - edge[u][i];
					if(slack[i] > ex)
					{
						slack[i] = ex;
						prev[i] = u;
					}
				}
				else
				{
					yckd[i] = true;
					prev[i] = u;
					Q.push((i<<1)|1);
				}
			}
		}
	}
	return false;
}

void agument(int u)
{
	while(u != -1)
	{
		int pv = xmate[prev[u]];
		ymate[u] = prev[u];
		xmate[prev[u]] = u;
		u = pv;
	}
}

int KMMatch()
{
	int i, j, mn;
	memset(ly, 0, sizeof(ly));
	for(i = 0; i < n; i++)
	{
		lx[i] = -INF;
		for(j = 0; j < n; j++)
		{
			lx[i] = lx[i]>edge[i][j]?lx[i]:edge[i][j];
		}
	}
	memset(xmate, -1, sizeof(xmate));
	memset(ymate, -1, sizeof(ymate));
	bool agu = true;
	for(mn = 0; mn < n; mn++)
	{
		if(agu)
		{
			memset(xckd, 0, sizeof(xckd));
			memset(yckd, 0, sizeof(yckd));
			for(i = 0; i < n; i++)
				slack[i] = INF;
			while(!Q.empty())
				Q.pop();
			xckd[mn] = true;
			Q.push(mn<<1);
		}
		if(bfs())
		{
			agu = true;
			continue;
		}
		int ex = INF;
		mn--;
		agu = false;
		for(i = 0; i < n; i++)
			if(!yckd[i])
				ex = ex<slack[i]?ex:slack[i];
		for(i = 0; i < n; i++)
		{
			if(xckd[i])
				lx[i] -= ex;
			if(yckd[i])
				ly[i] += ex;
			slack[i] -= ex;
		}
		for(i = 0; i < n; i++)
			if(!yckd[i] && slack[i] == 0)
			{
				yckd[i] = true;
				Q.push((i<<1)|1);
			}
	}
	int cost = 0;
	for(i = 0; i < n; i++)
		cost += edge[i][xmate[i]];
	return cost;
}

转载于:https://my.oschina.net/windmissing/blog/690471

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值