KM算法 (lzz)

#include<cstdio>
#include<cstring>
const int N=510;
const int INF=1e18;
int n,m;
int val[N][N];
int match[N];
bool vis[N];
int ex[N],ey[N],slack[N];
int pre[N];
int max(int a,int b)
{
	if(a>b)return a;
	return b;
}
void add_new(int x)
{
	int k,i,j;
	int y=0,y_=0,a,b;
	for(k=0;k<=n;k++)
	{
		pre[k]=0;
		slack[k]=INF;
		vis[k]=false;
	}
	match[y]=x;
	while(true)
	{
		a=match[y]; vis[y]=true; b=INF;
		for(k=1;k<=n;k++)
		{
			if(vis[k])continue;
			if(ex[a]+ey[k]-val[a][k]<slack[k])
			{
				slack[k]=ex[a]+ey[k]-val[a][k];
				pre[k]=y;
			}
			if(slack[k]<b)
			{
				b=slack[k];
				y_=k;
			}
		}
		for(k=0;k<=n;k++)
		{
			if(vis[k])
			{
				ex[match[k]]-=b;
				ey[k]+=b;
			}
			else slack[k]-=b;
		}
		y=y_;
		if(match[y]==-1)break;
	}
	while(y)
	{
		match[y]=match[pre[y]];
		y=pre[y];
	}
	return;
}

void KM()
{
	int k,i,j;
	memset(match,-1,sizeof(match));
	memset(ex,0,sizeof(ex));
	memset(ey,0,sizeof(ey));
	for(k=1;k<=n;k++)add_new(k);
	return;
}
int main()
{
	int k,i,j;
	int a,b,c;
	int sum=0;
	scanf("%d%d",&n,&m);
	for(k=1;k<=n;k++)
	for(i=1;i<=n;i++)
	{
		val[k][i]=-INF;
	}
	for(k=0;k<m;k++)
	{
		scanf("%d%d%d",&a,&b,&c);
		val[a][b]=c;
	}
	KM();
	
	for(k=1;k<=n;k++)sum+=val[match[k]][k];
	printf("%d\n",sum);
    for(k=1;k<=n;k++)printf("%d ",match[k]);
    printf("\n");
	return 0;
}
posted @ 2022-03-07 20:35  wild_chicken  阅读(80)  评论(0)    收藏  举报