KM algorithm [perfect matching of weighted bipartite graph]

First orz litble - KM algorithm

Why use KM algorithm

Because of some problems, the card fee flow is crazy
Compared with the cost flow, the KM algorithm has higher efficiency.

Algorithm flow

We set an expected value [feasible top mark]
for each point. For the point on the left, it is the point on the right that is expected to match the weight. For the point
on the right, it is expected to be above the expectation of the point on the left. How much can you contribute

Two points can match if and only if the sum of their expected values ​​is the weight of the edge

The expectation of initializing all left points at the beginning is the maximum value of their outgoing edges, because in the ideal case, of course, each point matches the one that it can match the largest. The
right point expectation is 0

Then we match one by one. When a point fails to match, the expectation of all left points is too high.
We find the point with the smallest expected difference from the matched point from the points that are not matched by the right point, and subtract this expectation from all matched left points. [makes one more point that can be matched], then add this expected value to the matched right point [because it is necessary to ensure that the matched point can still be matched],
and then continue to try to match
until all points are matched

board:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 405,maxm = 100005,INF = 1000000000;
inline int read(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    return out * flag;
}
int w[maxn][maxn],expa[maxn],expb[maxn],visa[maxn],visb[maxn],cp[maxn],dl[maxn];
int n;
bool dfs(int u){
    visa[u] = true;
    REP(i,n) if (!visb[i]){
        int kl = expa[u] + expb[i] - w[u][i];
        if (kl == 0){
            visb[i] = true;
            if (!cp[i] || dfs(cp[i])){
                cp[i] = u; return true;
            }
        }
        else dl[i] = min(dl[i],kl);
        
    }
    return false;
}
int solve(){
    REP(i,n) expa[i] = expb[i] = cp[i] = 0;
    REP(i,n) REP(j,n) expa[i] = max(expa[i],w[i][j]);
    REP(i,n){
        REP(j,n) dl[j] = INF;
        while (true){
            REP(j,n) visa[j] = false,visb[j] = false;
            if (dfs(i)) break;
            int kl = INF;
            REP(j,n) if (!visb[j]) kl = min(kl,dl[j]);
            REP(j,n){
                if (visa[j]) expa[j] -= kl;
                if (visb[j]) expb[j] += kl;
                else dl[j] -= kl;
            }
        }
    }
    int re = 0;
    REP(i,n) re += w[cp[i]][i];
    return re;
}
int main(){
    n = read();
    REP(i,n) REP(j,n) w[i][j] = read();
    printf("%d\n",solve());
    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325312361&siteId=291194637