UVA11383 Golden Tiger Claw

题意:

给定一个N*N的矩阵,每个位置有一个正整数w(i,j)
要求对每行赋一个值row(i),每列赋一个值col(i)
使得在满足对于任意w(i,j),有w(i,j)<=row(i)+col(j)的前提下,最小化所有row(i)和col(i)之和
N<=500
链接

思路:

例题。
考虑KM算法里的不等式l(x)+l(y)>=w(i,j)
跑完KM算法后所有l(x)+l(y)即为最小
直接套KM算法即可(这里和带权最大完美没有关系~~)

注意:

第一次写KM算法。
要注意变量d和vis2[i]的赋值

code:

#include<bits/stdc++.h>
using namespace std;
const int N=505;
int n;
int lk[N][N],lb1[N],lb2[N],match[N],slack[N];
bool vis1[N],vis2[N];
inline int read()
{
	int s=0,w=1; char ch=getchar();
	for(;!isdigit(ch);ch=getchar())if(ch=='-')w=-1;
	for(;isdigit(ch);ch=getchar())s=(s<<1)+(s<<3)+(ch^48);
	return s*w;
}
bool dfs(int x)
{
	vis1[x]=1;
	for(int i=1;i<=n;++i)
	{
		if(vis2[i]) continue;
		int gap=lb1[x]+lb2[i]-lk[x][i];
		if(!gap)
		{
			vis2[i]=1;
			if(match[i]==-1||dfs(match[i]))
			{
				match[i]=x;
				return true;
			} 
		}
		else slack[i]=min(slack[i],gap);
	}
	return false;
}
inline void km()
{
	for(int i=1;i<=n;++i)match[i]=-1;
	for(int i=1;i<=n;++i)lb2[i]=0;
	for(int i=1;i<=n;++i)
	{
		lb1[i]=lk[i][1];
		for(int j=2;j<=n;++j)
			lb1[i]=max(lb1[i],lk[i][j]);
	}
	for(int i=1;i<=n;++i)
	{
		for(int j=1;j<=n;++j)slack[j]=1e9;
		while(1)
		{
			for(int j=1;j<=n;++j)vis1[j]=vis2[j]=0;
			if(dfs(i)) break;
			int d=1e9;
			for(int j=1;j<=n;++j)
				if(!vis2[j])d=min(d,slack[j]);
			for(int j=1;j<=n;++j)
			{
				if(vis1[j]) lb1[j]-=d;
				if(vis2[j]) lb2[j]+=d;
				else slack[j]-=d;
			}
		}
	}
	int ans=0;
	for(int i=1;i<=n;++i)printf("%d ",lb1[i]);
	puts("");
	for(int i=1;i<=n;++i)printf("%d ",lb2[i]);
	for(int i=1;i<=n;++i)ans+=lb1[i]+lb2[i];
	puts("");
	printf("%d
",ans);
}
int main()
{
	while(~scanf("%d",&n))
	{
		for(int i=1;i<=n;++i)
			for(int j=1;j<=n;++j)
				lk[i][j]=read();
		km();
	}
	return 0;
}

这里推荐一个KM算法讲得比较形象的:这里

原文地址:https://www.cnblogs.com/zmyzmy/p/12494676.html