带权二分图最佳匹配(KM)

带权二分图最佳匹配(KM)

#include<iostream> 
#include<cstdio>
#include<cstring>
using namespace std;
int head[1010],to[100010],w[1010][1010],nxt[100010],link[100010],dis[100010],tot=0;
bool vis[1010];
int INF=0x7f7f7f7f;
void add(int u,int v)
{
    
    
	to[++tot]=v,nxt[tot]=head[u],head[u]=tot;
	return;
}
bool find(int x)
{
    
    
	int v;
	for(int i=head[x];i;i=nxt[i])
		if(!vis[v=to[i]]&&dis[i]+dis[v]==w[i][v])
		{
    
    
			vis[v]=1;
			if(!link[v]||find(link[v])){
    
    link[v]=x,link[x]=v;return 1;}
		}
	return 0;
}
int KM()
{
    
    
	int ans=0,sum,i,j;
	memset(dis,0,sizeof(dis));
	for(i=1;i<=n;++i)
		for(dis[i]=-INF,j=n+1;j<=n+n;++j)
			dis[i]=dis[i]<w[i][j]?w[i][j]:dis[i];
	memset(link,0,sizeof(link));
	for(i=1;i<=n;++i)
		while(1)
		{
    
    
			memset(vis,0,sizeof(vis));
			if(find(i))break;
			for(sum=INF,j=1;j<=n;++j)
			{
    
    
				if(vis[j])
					for(k=n+1;k<=n+n;++k)
						if(!vis[k])sum=min(sum,dis[j]+dis[k]-w[j][k]);
				if(sum==INF)return -1;
				for(j=1;j<=n;++j)
					if(vis[j])dis[j]-=sum;
				for(j=n+1;j<=n+n;++j)
					if(vis[j])dis[j]+=sum;
			}
		}
	for(i=1;i<=n;++i)
		if(link[i])ans+=w[link[i]][i];
	return ans;
}
int main()
{
    
    
	int n,m,e,u,v,wt,i,ans;
	memset(head,0,sizeof(head));
	memset(vis,0,sizeof(vis));
	memset(link,0,sizeof(link));
	scanf("%d%d%d",&n,&m,&e);
	for(int i=0;i<e;++i)
		scanf("%d%d%d",&u,&v,&w[u][v]),v+=n,add(u,v),add(v,u);
	printf("%d",KM());
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_46975572/article/details/118117946