二分图最佳匹配

由于最大匹配有很多 毒瘤的出题人就想到给每条边加个权然后整一个权值最大

于是喜提最佳匹配

大佬的blog真的好 彻底明白了 传送门

这个问题主要是基于完全图匹配的

如果不是完全图就补一个价值为0就行

算法中就是这两个点用了但是没有产生价值

一定比不选还要差...

算法主要流程:

1.找到左部图中的待匹配顶点

2.直接去右部图匹配

3.如果右部图没有匹配点 就更改label(类似于网络流的增广路)

4.循环2,3直到找到匹配为止

Code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<iostream>
#include<iomanip>
#define itn int
#define ms(a,b) memset(a,b,sizeof a)
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define inf 2147483647
using namespace std;
typedef long long ll;
ll read() {
    ll as = 0,fu = 1;
    char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') fu = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        as = as * 10 + c - '0';
        c = getchar();
    }
    return as * fu;
}
//head
const int N = 3006;
int n,ans; 
int v[N][N];
int match[N];
int visx[N],visy[N];
int lx[N],ly[N];//label

bool dfs(int x) {
    visx[x] = 1;
    rep(y,1,n) {
        if(!visy[x] || (lx[x] + ly[y] == v[x][y])) {
            visy[y] = 1;
            if(!match[y] || dfs(match[y])) {
                match[y] = x;
                return 1;
            }
        }
    }
    return 0;
}

void init() {
    ms(lx,0),ms(ly,0),ms(v,0);
    ms(match,0);    
}

void solve() {
    init();
    rep(i,1,n) {
        rep(j,1,n) v[i][j] = read();
        int tmp = 0;
        rep(j,1,n) tmp = max(tmp,v[i][j]);
        lx[i] = tmp;
    }
    rep(i,1,n) {
        while(1) {
            int d = inf;
            ms(visx,0),ms(visy,0);
            if(dfs(i)) break;
            rep(j,1,n) {
                if(!visx[j]) continue;
                rep(k,1,n) if(!visy[k]) d = min(d,lx[j] + ly[k] - v[j][k]);
            }
            if(d == inf) {
                puts("-1");
                return;
            }
            rep(j,1,n) if(visx[j]) lx[j] -= d;
            rep(k,1,n) if(visy[k]) ly[k] += d;
        }
    }
    ans = 0;
    rep(i,1,n) ans += v[match[i]][i];
    printf("%d\n",ans);
}


int main() {
    while(~scanf("%d",&n)) solve();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/yuyanjiaB/p/9925450.html
今日推荐