例题:牛客多校第五场-room
const int MAXN=105;
int w[MAXN][MAXN];//边权
int la[MAXN],lb[MAXN];//左、右部点的顶标
bool va[MAXN],vb[MAXN];//访问标记:是否在交错树中
int match[MAXN];//右部点匹配了哪一个左部点
int n,delta;
bool dfs(int x){
va[x]=1;//访问标记,x在交错树中
for(int y=1;y<=n;y++){
if(vb[y]) continue;
if(la[x]+lb[y]-w[x][y]==0){//相等子图
vb[y]=1;//访问标记:y在交错树中
if(!match[y]||dfs(match[y])){
match[y]=x;
return true;
}
}else delta=min(delta,la[x]+lb[y]-w[x][y]);
}
return false;
}
int KM(){
for(int i=1;i<=n;i++){
la[i]=-(1<<30);//-INF
lb[i]=0;
for(int j=1;j<=n;j++){
la[i]=max(la[i],w[i][j]);
}
}
for(int i=1;i<=n;i++){
while(true){ //直到左部点找到匹配
memset(va,0,sizeof(va));
memset(vb,0,sizeof(vb));
delta = 1<<30;//INF
if(dfs(i)) break;
for(int j=1;j<=n;j++){//修改顶标
if(va[j]) la[j]-=delta;
if(vb[j]) lb[j]+=delta;
}
}
}
int ans=0;
for(int i=1;i<=n;i++) ans+=w[match[i]][i];
return ans;
}
void init(){
memset(match,0,sizeof(match));
}