POJ2195Going Home【KM】
题意:
给一个矩阵,m代表人H代表房子,现在想让人移动最少的步数回到房子中
分析:
可用二分图和网络流来写
二分图:X集合为人Y集合为房子,人与每个房子的连一条边为-dist的边即可,求出最大权值,然后取反即可
网络流:用费用流来做,人与房子之间建立容量为1,费用为dist的边,求出最小费用即可
由于人与每个房子之间有有边,所以我用的邻接矩阵处理的
二分图代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <map> 5 #include <vector> 6 #include <cmath> 7 using namespace std; 8 9 const int maxn = 105; 10 const int INF = 1000000000; 11 12 typedef pair<int, int> PII; 13 vector<PII> v[2]; 14 15 16 int n_cnt; 17 int W[maxn][maxn]; 18 int Lx[maxn], Ly[maxn]; 19 int Left[maxn]; 20 bool S[maxn], T[maxn]; 21 22 bool match(int i) { 23 S[i] = true; 24 for(int j = 1; j <= n_cnt; j++) if(Lx[i] + Ly[j] == W[i][j] && !T[j]) { 25 T[j] = true; 26 if(!Left[j] || match(Left[j])) { 27 Left[j] = i; 28 return true; 29 } 30 } 31 return false; 32 } 33 34 35 void update() { 36 int a = INF; 37 for(int i = 1; i <= n_cnt; i++) if(S[i]) { 38 for(int j = 1; j <= n_cnt; j++) if(!T[j]) { 39 a = min(a, Lx[i] + Ly[j] - W[i][j]); 40 } 41 } 42 for(int i = 1; i <= n_cnt; i++) { 43 if(S[i]) Lx[i] -= a; 44 if(T[i]) Ly[i] += a; 45 } 46 } 47 48 void KM() { 49 for(int i = 1; i <= n_cnt; i++) { 50 Left[i] = Lx[i] = Ly[i] = 0; 51 for(int j = 1; j <= n_cnt; j++) { 52 Lx[i] = max(Lx[i], W[i][j]); 53 } 54 } 55 for(int i = 1; i <= n_cnt; i++) { 56 for(;;) { 57 for(int j = 1; j <= n_cnt; j++) S[j] = T[j] = 0; 58 if(match(i)) break; 59 else update(); 60 } 61 } 62 } 63 64 int dist(PII p1, PII p2) { 65 return fabs(p1.first - p2.first) + fabs(p1.second - p2.second); 66 } 67 68 int main() { 69 int n, m; 70 // freopen("a.txt","r",stdin); 71 while(scanf("%d %d",&n, &m) && n + m) { 72 char mat[maxn][maxn]; 73 memset(W, 0, sizeof(W)); 74 v[0].clear(); v[1].clear(); 75 for(int i = 0; i < n; i++) { 76 scanf("\n%s",mat[i]); 77 // puts(mat[i]); 78 } 79 for(int i = 0; i < n; i++) { 80 for(int j = 0; j < m; j++) { 81 if(mat[i][j] == 'm') 82 v[0].push_back(make_pair(i, j)); 83 else if(mat[i][j] == 'H') 84 v[1].push_back(make_pair(i, j)); 85 } 86 } 87 n_cnt = v[0].size(); 88 // printf("n == %d\n",n_cnt); 89 for(int i = 0; i < n_cnt; i++) { 90 for(int j = 0; j < n_cnt; j++) { 91 W[i + 1][j + 1] = -dist(v[0][i], v[1][j]); 92 } 93 } 94 KM(); 95 int ans = 0; 96 for(int i = 1; i <= n_cnt; i++) { 97 ans += Lx[i] + Ly[i]; 98 } 99 printf("%d\n",-ans); 100 } 101 return 0; 102 }