二分图KM算法

详情看下面链接

链接:https://blog.csdn.net/wuxinxiaohuangdou/article/details/14056987

链接:https://blog.csdn.net/chenshibo17/article/details/79933191

KM模板(标注自己的理解):

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<string>
using namespace std;
typedef long long ll;
const int MAXN=305;
const int INF=0x3f3f3f3f;
int f[MAXN][MAXN];
int nx[MAXN],ny[MAXN];
bool vis_nx[MAXN],vis_ny[MAXN];
int match[MAXN];
int slack[MAXN];
int n;
bool dfs(int x)
{
	vis_nx[x]=1;
	for(int i=0;i<n;i++)
	{
		if(vis_ny[i])continue;
		int gap=nx[x]+ny[i]-f[x][i];
		if(gap==0)
		{
		    vis_ny[i]=1;
			if(match[i]==-1||dfs(match[i]))
			{
				match[i]=x;
				return true;
			}	
		} 
		else{
			slack[i]=min(slack[i],gap);
		}
	}
	return false;
}
int KM()
{
	memset(match,-1,sizeof(match));
	memset(ny,0,sizeof(ny));
	int i,j,k;
	for(i=0;i<n;i++)
	{
		nx[i]=f[i][0];
		for(j=1;j<n;j++)
		{
			nx[i]=max(nx[i],f[i][j]);//初始化为最大值
		}
	}
	for(i=0;i<n;i++)
	{
		fill(slack,slack+n,INF);//找到未匹配的和其自身最优匹配差值最小的,这样损失最小
		while(1)
		{
			memset(vis_nx,false,sizeof(vis_nx));
			memset(vis_ny,false,sizeof(vis_ny));
			if(dfs(i))break;
			int d=INF;
			for(j=0;j<n;j++)
			{
				if(!vis_ny[j])d=min(d,slack[j]);
			}
			for(j=0;j<n;j++)
			{
				if(vis_nx[j])nx[j]-=d;
				if(vis_ny[j])ny[j]+=d;
				else slack[j]-=d;
			}
		}
	}
	int res=0;
	for(i=0;i<n;i++)
	{
	    res+=f[match[i]][i];	
	}
	return res;
}
int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		int i,j;
		for(i=0;i<n;i++)
		{
			for(j=0;j<n;j++)
			{
				scanf("%d",&f[i][j]);
			}
		}
		printf("%d\n",KM());
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值