[题目链接]
http://poj.org/problem?id=2195
[算法]
KM算法求二分图带权最小匹配
[代码]
#include <algorithm> #include <bitset> #include <cctype> #include <cerrno> #include <clocale> #include <cmath> #include <complex> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #include <deque> #include <exception> #include <fstream> #include <functional> #include <limits> #include <list> #include <map> #include <iomanip> #include <ios> #include <iosfwd> #include <iostream> #include <istream> #include <ostream> #include <queue> #include <set> #include <sstream> #include <stdexcept> #include <streambuf> #include <string> #include <utility> #include <vector> #include <cwchar> #include <cwctype> #include <stack> #include <limits.h> using namespace std; #define MAXN 5010 const int inf = 2e9; int i,j,l1,l2,n,m,delta; int match[MAXN],la[MAXN],lb[MAXN]; bool visiteda[MAXN],visitedb[MAXN]; int w[MAXN][MAXN]; pair<int,int> man[MAXN],house[MAXN]; char mp[MAXN][MAXN]; inline int dist(pair<int,int> a,pair<int,int> b) { return abs(a.first - b.first) + abs(a.second - b.second); } inline bool dfs(int u) { int v; visiteda[u] = true; for (v = 1; v <= l1; v++) { if (!visitedb[v]) { if (la[u] + lb[v] - w[u][v] == 0) { visitedb[v] = true; if (!match[v] || dfs(match[v])) { match[v] = u; return true; } } } } return false; } inline int KM() { int i,j,k,ret; for (i = 1; i <= l1; i++) { la[i] = -inf; lb[i] = 0; match[i] = 0; for (j = 1; j <= l1; j++) la[i] = max(la[i],w[i][j]); } for (i = 1; i <= l1; i++) { while (true) { for (j = 1; j <= l1; j++) visiteda[j] = visitedb[j] = false; if (dfs(i)) break; delta = inf; for (j = 1; j <= l1; j++) { if (visiteda[j]) { for (k = 1; k <= l1; k++) { if (!visitedb[k]) delta = min(delta,la[j] + lb[k] - w[j][k]); } } } for (j = 1; j <= l1; j++) { if (visiteda[j]) la[j] -= delta; if (visitedb[j]) lb[j] += delta; } } } ret = 0; for (i = 1; i <= l1; i++) ret += w[match[i]][i]; return ret; } int main() { while (scanf("%d%d",&n,&m) && (n || m)) { l1 = l2 = 0; for (i = 1; i <= n; i++) scanf("%s",mp[i] + 1); for (i = 1; i <= n; i++) { for (j = 1; j <= m; j++) { if (mp[i][j] == 'm') man[++l1] = make_pair(i,j); if (mp[i][j] == 'H') house[++l2] = make_pair(i,j); } } for (i = 1; i <= l1; i++) { for (j = 1; j <= l1; j++) { w[i][j] = -dist(man[i],house[j]); } } printf("%d ",-KM()); } return 0; }