题意:
给定一个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算法讲得比较形象的:这里