由于最大匹配有很多 毒瘤的出题人就想到给每条边加个权然后整一个权值最大
于是喜提最佳匹配
大佬的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 ",ans); } int main() { while(~scanf("%d",&n)) solve(); return 0; }