在xi 与 yi 之间建立一条边值为a[i][j]的边, 然后跑km算法 2分图最优匹配。
原来的km+hunger跑法T了, 拿了一个新的板子, 新的写法是将这原来的找新的最小的d放在了上一次的残留图上,从而减小复杂度, 但是个人还不是很理解为什么最小的d下一次出现的位置一定是这次出现的位置的对应的x的点。
复杂度:n3
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 const int inf = 0x3f3f3f3f; 5 const LL INF = 0x3f3f3f3f3f3f3f3f; 6 const int N = 210; 7 int val[N][N]; 8 LL lx[N],ly[N]; 9 int linky[N]; 10 LL pre[N]; 11 bool vis[N]; 12 bool visx[N],visy[N]; 13 LL slack[N]; 14 int n; 15 void bfs(int k) 16 { 17 LL px, py = 0,yy = 0, d; 18 memset(pre, 0, sizeof(LL) * (n+2)); 19 memset(slack, inf, sizeof(LL) * (n+2)); 20 linky[py]=k; 21 do{ 22 px = linky[py],d = INF, vis[py] = 1; 23 for(int i = 1; i <= n; i++) 24 if(!vis[i]){ 25 if(slack[i] > lx[px] + ly[i] - val[px][i]) 26 slack[i] = lx[px] + ly[i] - val[px][i], pre[i] = py; 27 if(slack[i] < d) d = slack[i], yy = i; 28 } 29 for(int i = 0; i <= n; i++) 30 if(vis[i]) lx[linky[i]] -= d, ly[i] += d; 31 else slack[i] -= d; 32 py = yy; 33 }while(linky[py]); 34 while(py) linky[py] = linky[pre[py]] , py=pre[py]; 35 } 36 void KM() 37 { 38 memset(lx, 0, sizeof(int)*(n+2)); 39 memset(ly, 0, sizeof(int)*(n+2)); 40 memset(linky, 0, sizeof(int)*(n+2)); 41 for(int i = 1; i <= n; i++) 42 memset(vis, 0, sizeof(bool)*(n+2)), bfs(i); 43 } 44 int main() 45 { 46 int T; 47 scanf("%d", &T); 48 for(int _i = 1; _i <= T; _i++){ 49 scanf("%d", &n); 50 for(int i = 1; i <= n; i++){ 51 for(int j = 1; j <= n; j++){ 52 scanf("%d", &val[i][j]); 53 val[i][j] = -val[i][j]; 54 } 55 } 56 KM(); 57 LL ans = 0; 58 for(int i = 1; i <= n; ++i) 59 ans += lx[i] + ly[i]; 60 printf("Case #%d: %I64d\n", _i, -ans); 61 } 62 return 0; 63 }
原文地址:https://www.cnblogs.com/MingSD/p/9436476.html
时间: 2024-11-13 09:32:17