二分图完美匹配模板
这里讲的都是最大权完美匹配。如果求最小权只需把边权改成负数即可
dfs版(慢,代码简单)
#include<bits/stdc++.h>
using namespace std ;
const int M=405 ;
int n,mat[M];
long long Lx[M],Ly[M],A[M][M];
long long slack;
bool S[M],T[M];
bool dfs(int x) {
S[x]=1 ;
for (int y=1 ; y<=n; y++) {
if (T[y])continue ;
long long tmp=Lx[x]+Ly[y]-A[x][y];
if (!tmp) {
T[y]=1 ;
if (!mat[y]||dfs(mat[y])) {
mat[y]=x;
return 1 ;
}
} else {
slack=min(slack,tmp);
}
}
return 0 ;
}
void update() {
for (int i=1 ; i<=n; i++) {
if (S[i])Lx[i]-=slack;
if (T[i])Ly[i]+=slack;
}
}
int main() {
int Tk,cas=0 ;
scanf ("%d" ,&Tk);
while (Tk--) {
scanf ("%d" ,&n);
for (int i=1 ; i<=n; i++) {
for (int j=1 ; j<=n; j++) {
scanf ("%lld" ,&A[i][j]);
}
}
for (int i=1 ; i<=n; i++) {
Lx[i]=-2e18 ;
Ly[i]=mat[i]=0 ;
for (int j=1 ; j<=n; j++) {
Lx[i]=max(Lx[i],A[i][j]);
}
}
for (int i=1 ; i<=n; i++) {
int cnt=0 ;
while (1 ) {
for (int j=1 ; j<=n; j++) {
S[j]=T[j]=0 ;
}
slack=2e18 ;
if (bfs(i))break ;
else update();
cnt++;
if (cnt>n+1 )return 0 ;
}
}
long long ans=0 ;
for (int i=1 ; i<=n; i++) {
ans+=Lx[i]+Ly[i];
}
printf ("Case #%d: %I64d\n" ,++cas,ans);
}
return 0 ;
}
bfs版(快,代码复杂)
#include<bits/stdc++.h>
using namespace std ;
const int M=405 ;
const long long inf=1e18 ;
int n;
bool vis[M];
int link[M],way[M];
long long Lx[M],Ly[M],mi[M],A[M][M];
void km() {
memset (link,-1 ,sizeof (link));
for (int i=1 ; i<=n; i++) {
link[0 ]=i;
int y=0 ;
memset (vis,0 ,sizeof (vis));
memset (mi,63 ,sizeof (mi));
do {
vis[y]=1 ;
int x=link[y],yy;
long long slack=inf;
for (int j=1 ; j<=n; j++) {
if (!vis[j]) {
long long tmp=Lx[x]+Ly[j]-A[x][j];
if (tmp<mi[j])mi[j]=tmp,way[j]=y;
if (mi[j]<slack)slack=mi[j],yy=j;
}
}
for (int j=0 ; j<=n; j++) {
if (vis[j])Lx[link[j]]-=slack,Ly[j]+=slack;
else mi[j]-=slack;
}
y=yy;
} while (~link[y]);
do {
int yy=way[y];
link[y]=link[yy];
y=yy;
} while (y);
}
}
long long solve() {
long long ans=0 ;
for (int i=1 ; i<=n; i++)ans+=Lx[i]+Ly[i];
return ans;
}
int main() {
int T,cas=0 ;
scanf ("%d" , &T);
while (T--) {
scanf ("%d" ,&n);
for (int i=1 ; i<=n; i++) {
for (int j=1 ; j<=n; j++) {
scanf ("%lld" ,&A[i][j]);
}
}
km();
printf ("Case #%d: %I64d\n" ,++cas,solve());
}
}