Maximum-weight matching in a general graph: Edmonds’ blossom algorithm with dual variables (primal–dual), with an adjacency matrix, or so. For bipartite graphs use the Hungarian algorithm (Assignment Problem); for a bitmask DP is simpler.

VariantReduction
maximum weight matching (any size)the code below, weights (drop non-positive edges)
maximum weight among maximum cardinality matchingsadd to every weight
minimum weight perfect matchingweight with $C > \sum
Chinese postman, T-joinsodd-degree vertices, shortest-path distances, min-weight perfect matching (Euler Tours)
DP over subsets pairing the lowest unpaired vertex,
struct WeightedBlossom {                                      // maximum weight matching, weights > 0, O(n^3)
    struct E { int u, v; ll w; };
    int N, NX; vector<vector<E>> g; vector<ll> lab;
    vector<int> match, slack, st, par, S, aux; vector<vector<int>> floFrom, flo; queue<int> q; int stamp = 0;
    WeightedBlossom(int n) : N(n), NX(n), g(2 * n + 1, vector<E>(2 * n + 1)), lab(2 * n + 1), match(2 * n + 1), slack(2 * n + 1),
        st(2 * n + 1), par(2 * n + 1), S(2 * n + 1), aux(2 * n + 1), floFrom(2 * n + 1, vector<int>(n + 1)), flo(2 * n + 1) {
        for (int u = 1; u <= N; u++) for (int v = 1; v <= N; v++) g[u][v] = {u, v, 0};
    }
    void addEdge(int u, int v, ll w) {                       // 0-indexed; keeps the heaviest parallel edge
        u++, v++; if (u == v) return;
        w = max(w, g[u][v].w); g[u][v].w = g[v][u].w = w;
    }
    ll eDelta(const E& e) const { return lab[e.u] + lab[e.v] - g[e.u][e.v].w * 2; }
    void updSlack(int u, int x) { if (!slack[x] || eDelta(g[u][x]) < eDelta(g[slack[x]][x])) slack[x] = u; }
    void setSlack(int x) { slack[x] = 0; for (int u = 1; u <= N; u++) if (g[u][x].w > 0 && st[u] != x && S[st[u]] == 0) updSlack(u, x); }
    void qPush(int x) { if (x <= N) q.push(x); else for (int t : flo[x]) qPush(t); }
    void setSt(int x, int b) { st[x] = b; if (x > N) for (int t : flo[x]) setSt(t, b); }
    int getPr(int b, int xr) {
        int pr = find(all(flo[b]), xr) - flo[b].begin();
        if (pr & 1) { reverse(flo[b].begin() + 1, flo[b].end()); return sz(flo[b]) - pr; }
        return pr;
    }
    void setMatch(int u, int v) {
        E e = g[u][v]; match[u] = e.v;
        if (u <= N) return;
        int xr = floFrom[u][e.u], pr = getPr(u, xr);
        for (int i = 0; i < pr; i++) setMatch(flo[u][i], flo[u][i ^ 1]);
        setMatch(xr, v); rotate(flo[u].begin(), flo[u].begin() + pr, flo[u].end());
    }
    void augment(int u, int v) {
        for (;;) {
            int xnv = st[match[u]]; setMatch(u, v);
            if (!xnv) return;
            setMatch(xnv, st[par[xnv]]); u = st[par[xnv]], v = xnv;
        }
    }
    int lca(int u, int v) {
        for (++stamp; u || v; swap(u, v)) {
            if (!u) continue;
            if (aux[u] == stamp) return u;
            aux[u] = stamp; u = st[match[u]];
            if (u) u = st[par[u]];
        }
        return 0;
    }
    void addBlossom(int u, int anc, int v) {
        int b = N + 1;
        while (b <= NX && st[b]) ++b;
        if (b > NX) ++NX;
        lab[b] = S[b] = 0; match[b] = match[anc]; flo[b] = {anc};
        auto blossom = [&](int x) { for (int y; x != anc; x = st[par[y]]) flo[b].push_back(x), flo[b].push_back(y = st[match[x]]), qPush(y); };
        blossom(u); reverse(flo[b].begin() + 1, flo[b].end()); blossom(v);
        setSt(b, b);
        for (int x = 1; x <= NX; x++) g[b][x].w = g[x][b].w = 0;
        for (int x = 1; x <= N; x++) floFrom[b][x] = 0;
        for (int xs : flo[b]) {
            for (int x = 1; x <= NX; x++) if (g[b][x].w == 0 || eDelta(g[xs][x]) < eDelta(g[b][x])) g[b][x] = g[xs][x], g[x][b] = g[x][xs];
            for (int x = 1; x <= N; x++) if (floFrom[xs][x]) floFrom[b][x] = xs;
        }
        setSlack(b);
    }
    void expandBlossom(int b) {
        for (int t : flo[b]) setSt(t, t);
        int xr = floFrom[b][g[b][par[b]].u], pr = getPr(b, xr);
        for (int i = 0; i < pr; i += 2) {
            int xs = flo[b][i], xns = flo[b][i + 1];
            par[xs] = g[xns][xs].u; S[xs] = 1; S[xns] = slack[xs] = slack[xns] = 0; qPush(xns);
        }
        S[xr] = 1, par[xr] = par[b];
        for (int i = pr + 1; i < sz(flo[b]); i++) { int xs = flo[b][i]; S[xs] = -1; setSlack(xs); }
        st[b] = 0;
    }
    bool onFoundEdge(const E& e) {
        int u = st[e.u], v = st[e.v];
        if (S[v] == -1) {
            par[v] = e.u, S[v] = 1; slack[v] = 0;
            int nu = st[match[v]]; S[nu] = slack[nu] = 0; qPush(nu);
        } else if (S[v] == 0) {
            int anc = lca(u, v);
            if (!anc) { augment(u, v), augment(v, u); return true; }
            addBlossom(u, anc, v);
        }
        return false;
    }
    bool matching() {
        q = queue<int>();
        for (int x = 1; x <= NX; x++) { S[x] = -1, slack[x] = 0; if (st[x] == x && !match[x]) par[x] = S[x] = 0, qPush(x); }
        if (q.empty()) return false;
        for (;;) {
            while (sz(q)) {
                int u = q.front(); q.pop();
                if (S[st[u]] == 1) continue;
                for (int v = 1; v <= N; v++) if (g[u][v].w > 0 && st[u] != st[v]) {
                    if (eDelta(g[u][v]) == 0) { if (onFoundEdge(g[u][v])) return true; }
                    else updSlack(u, st[v]);
                }
            }
            ll d = LLONG_MAX;
            for (int b = N + 1; b <= NX; b++) if (st[b] == b && S[b] == 1) d = min(d, lab[b] / 2);
            for (int x = 1; x <= NX; x++) if (st[x] == x && slack[x]) {
                if (S[x] == -1) d = min(d, eDelta(g[slack[x]][x]));
                else if (S[x] == 0) d = min(d, eDelta(g[slack[x]][x]) / 2);
            }
            for (int u = 1; u <= N; u++) {
                if (S[st[u]] == 0) { if (lab[u] <= d) return false; lab[u] -= d; }
                else if (S[st[u]] == 1) lab[u] += d;
            }
            for (int b = N + 1; b <= NX; b++) if (st[b] == b && S[b] != -1) lab[b] += (S[b] == 0 ? 1 : -1) * d * 2;
            q = queue<int>();
            for (int x = 1; x <= NX; x++)
                if (st[x] == x && slack[x] && st[slack[x]] != x && eDelta(g[slack[x]][x]) == 0 && onFoundEdge(g[slack[x]][x])) return true;
            for (int b = N + 1; b <= NX; b++) if (st[b] == b && S[b] == 1 && lab[b] == 0) expandBlossom(b);
        }
    }
    pair<ll, int> solve() {                                   // {total weight, number of matched pairs}
        NX = N; st[0] = 0; fill(all(aux), 0);
        for (int i = 1; i <= N; i++) match[i] = 0, st[i] = i, flo[i].clear();
        ll wMax = 0;
        for (int u = 1; u <= N; u++) for (int v = 1; v <= N; v++) floFrom[u][v] = u == v ? u : 0, wMax = max(wMax, g[u][v].w);
        for (int u = 1; u <= N; u++) lab[u] = wMax;
        int num = 0; while (matching()) ++num;
        ll wei = 0;
        for (int u = 1; u <= N; u++) if (match[u] && match[u] < u) wei += g[u][match[u]].w;
        return {wei, num};
    }
    int mate(int v) const { return match[v + 1] ? match[v + 1] - 1 : -1; }
};

The labels start at and only decrease; the search stops when a free vertex’s label would reach 0, so the result maximises weight, not size. Vertices are 0-indexed outside, 1-indexed inside; super-vertices are blossoms.

ll maxWeightMatchingDP(int n, const vector<vector<ll>>& w) {  // w[u][v] (<= 0 means "no edge"), n <= 20
    vector<ll> dp(1 << n, 0);                                 // dp[mask]: best on the vertex set mask
    for (int mask = 1; mask < (1 << n); mask++) {
        int v = __builtin_ctz(mask), rest = mask & ~(1 << v);
        dp[mask] = dp[rest];                                  // v stays unmatched
        for (int u = v + 1; u < n; u++) if (rest >> u & 1 && w[v][u] > 0) dp[mask] = max(dp[mask], w[v][u] + dp[rest & ~(1 << u)]);
    }
    return dp[(1 << n) - 1];
}