1. 程式人生 > >二分圖最佳匹配

二分圖最佳匹配

由於最大匹配有很多 毒瘤的出題人就想到給每條邊加個權然後整一個權值最大

於是喜提最佳匹配

大佬的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; }