二分图完美匹配模板
这里讲的都是最大权完美匹配。如果求最小权只需把边权改成负数即可
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());
}
}