KMO(n^4)
int W[maxn][maxn],n;
int Lx[maxn],Ly[maxn];//顶标
int left[maxn];//left[i]为右边第i个点的编号
bool S[maxn],T[maxn]; //S[i]和T[i]为左或右第i个点是否已经被标记
bool match(int i)//找到增广路
{
S[i]=true;
for(int j=1;j<=n;j++)
{
if(Lx[i]+Ly[j]==W[i][j] && !T[j])//相等子图点
{
T[j]=true;
if(!left[j] || match(left[j]))//不存在连接向S中的点或连向S中的点没有连回来
{
left[j]=i;
return true;
}
}
}
return false;
}
void update()
{
int a=1<<30;
for(int i=1;i<=n;i++)
if(S[i])
for(int j=1;j<=n;j++)
if(!T[j])
{
a=min(a,Lx[i]+Ly[j]-W[i][j]);
}
for(int i=1;i<=n;i++)
{
if(S[i]) Lx[i]-=a;
if(T[i]) Ly[i]+=a;
}
}
void KM()
{
for(int i=1;i<=n;i++)//初始化
{
left[i]=Lx[i]=Ly[j]=0;
for(int j=1;j<=n;j++)
{
Lx[i]=max(Lx[i],W[i][j]);
}
}
/*
枚举S和T中的每一个元素
*/
for(int i=1;i<=n;i++)
{
for(;;)
{
for(int j=1;j<=n;j++)
{
S[j]=T[j]=0;
}
if(match(i)) break;
else update();
}
}
}