二分图最优匹配 模板

① 时间复杂度O(n^4)

#include <iostream>
#include <string.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1000;
int cx[maxn],cy[maxn],w[maxn][maxn],usex[maxn],usey[maxn],girl[maxn];
int slack[maxn];
int m,n,ans;
bool find(int x)
{
	usex[x]=1;
	for (int i=1;i<=m;i++)
	{
		if (w[x][i]==cx[x]+cy[i]&&usey[i]==0)
		{
			usey[i]=1;
			if (girl[i]==0||find(girl[i]))
			{
			   girl[i]=x;
			   return true;
			}
		}
	}
	return false;
}
int km()
{
	  for (int i=1;i<=n;i++)
	  {
	  	while (1)
	  	{
		memset(usex,0,sizeof(usex));
		memset(usey,0,sizeof(usey));
		int d=inf;
		if (find(i))break;
		for (int j=1;j<=n;j++)
		 {
		 	if (usex[j])
		 	{
		 		for (int k=1;k<=m;k++)
		 		if (!usey[k])
		 		d=min(d,cx[j]+cy[k]-w[j][k]);
			 }
		 }
		 if (d==inf)return -1;
		 for (int j=1;j<=n;j++)
		 if (usex[j]) cx[j]-=d;
		 for (int j=1;j<=m;j++)
		 if (usey[j]) cy[j]+=d;
	    }
	 }
	ans=0;
	for (int i=1;i<=m;i++)
	ans+=w[girl[i]][i];
	return ans;
}
int main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
   cin>>n>>m;
   memset(cx,0,sizeof(cx));
   memset(cy,0,sizeof(cy));
   for (int i=1;i<=n;i++)
    {
    	int d=0;
    	for (int j=1;j<=m;j++)
    	{
    		cin>>w[i][j];
    		d=max(d,w[i][j]);
		}
		cx[i]=d;
    }
    memset(girl,0,sizeof(girl));
	cout<<km()<<endl;
	return 0;
} 
上面的return -1指的是不存在完全匹配;
②O(n^3)

#include <iostream>
#include <string.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1000;
int cx[maxn],cy[maxn],w[maxn][maxn],usex[maxn],usey[maxn],girl[maxn];
int slack[maxn];
int n,ans;
bool find(int x)
{
	usex[x]=1;
	for (int i=1;i<=n;i++)
	{
		if (usey[i])
		continue;
		int gap=cx[x]+cy[i]-w[x][i];
		if (gap==0)
		{
			usey[i]=1;
			if (girl[i]==0||find(girl[i]))
			{
			   girl[i]=x;
			   return true;
			}
		}
		else
		slack[i]=min(slack[i],gap);
	}
	return false;
}
int km()
{
	  for (int i=1;i<=n;i++)
	  {
	  	memset(slack,inf,sizeof(slack));
	  	while (1)
	  	{
		memset(usex,0,sizeof(usex));
		memset(usey,0,sizeof(usey));
		int d=inf;
		if (find(i))break;
		for (int j=1;j<=n;j++)
		     if (!usey[j])
		     d=min(d,slack[j]);
		 if (d==inf)return -1;
		 for (int j=1;j<=n;j++)
		 {
		   if (usex[j]) cx[j]-=d;
		   if (usey[j]) cy[j]+=d;
		   else
		    slack[j]-=d;
	     }
	    }
	 }
	ans=0;
	for (int i=1;i<=n;i++)
	ans+=w[girl[i]][i];
	return ans;
}
int main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
   cin>>n;
   memset(cx,0,sizeof(cx));
   memset(cy,0,sizeof(cy));
   for (int i=1;i<=n;i++)
    {
    	int d=0;
    	for (int j=1;j<=n;j++)
    	{
    		cin>>w[i][j];
    		d=max(d,w[i][j]);
		}
		cx[i]=d;
    }
    memset(girl,0,sizeof(girl));
	cout<<km()<<endl;
	return 0;
} 




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值