http://acm.split.hdu.edu.cn/showproblem.php?pid=2255
带权匹配问题:
#include <stdio.h> #include <algorithm> #include <string.h> #include <vector> using namespace std; #define maxn 330 #define INF 0xfffffff int maps[maxn][maxn], vx[maxn], vy[maxn], used[maxn], lx[maxn], ly[maxn], s[maxn], n; ///vx[i]代表第i人是否在增广路上 ///used[i]代表第i个村庄是否被占用 ///lx[],ly[]代表人和村庄的顶标 int Find(int u) { vx[u] = 1; for(int i=1; i<=n; i++) { if(!vy[i] && lx[u]+ly[i] == maps[u][i]) { vy[i] = 1; if(!used[i] || Find(used[i])) { used[i] = u; return 1; } } else { s[i] = min(s[i], lx[u]+ly[i]-maps[u][i]); } } return 0; } int KM() { memset(used, 0, sizeof(used)); memset(lx, 0, sizeof(lx)); memset(ly, 0, sizeof(ly)); for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) lx[i] = max(maps[i][j], lx[i]);///初始化人的顶标 for(int i=1; i<=n; i++)///寻找最大匹配 { for(int j=1; j<=n; j++) s[j] = INF; while(1) { memset(vx, 0, sizeof(vx)); memset(vy, 0, sizeof(vy)); if(Find(i)) break;///找到增广路就退出,否则改变顶标,直到找到为止 int d = INF; for(int j=1; j<=n; j++) { if(!vy[j]) d=min(d, s[j]); } for(int j=1; j<=n; j++) { if(vx[j]) lx[j] -= d; if(vy[j]) ly[j] += d; } } } int ans = 0; for(int i=1; i<=n; i++) ans += maps[used[i]][i]; return ans; } int main() { while(scanf("%d", &n)!=EOF) { for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) scanf("%d", &maps[i][j]); printf("%d ", KM()); } return 0; }