POJ-2195 Going Home---KM算法求最小权值匹配(存负边)
Posted 努力努力再努力x
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ-2195 Going Home---KM算法求最小权值匹配(存负边)相关的知识,希望对你有一定的参考价值。
题目链接:
https://vjudge.net/problem/POJ-2195
题目大意:
给定一个N*M的地图,地图上有若干个man和house,且man与house的数量一致。man每移动一格需花费$1(即单位费用=单位距离),一间house只能入住一个man。现在要求所有的man都入住house,求最小费用。
思路:
每个man和house建立带权二分图,曼哈顿距离就是边的值,这里要求最小费用,也就是二分图最小权值匹配,但是KM算法求的是二分图最大权值匹配,所以此处用边的负数求最优匹配,求出来的答案的负数就是最小权匹配。
注意:题目说house最多100,但是没有说明man的范围,所以man应该最多100*100。
应该用house为二分图的X部,因为算法复杂度和X部点数有关,所以用点数少的house为X部
因为存的是负数,在预处理X部的顶标值初始化应该是-INF,不能是0
剩下的就是模板啦
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int maxx = 100 + 5;//house的上限 7 const int maxy = 10000 + 5;//man的上限 8 const int INF = 0x3f3f3f3f; 9 int cntx, cnty;//X部的点的数目,Y部点的数目 10 bool visx[maxx], visy[maxy];//是否加入增广路 11 int wx[maxx], wy[maxy];//顶标值 12 int cx[maxx], cy[maxy];//匹配的点 13 int minz;//顶标值和边权最小的差值 14 int Map[maxx][maxy];//保存边 15 16 bool dfs(int u) 17 { 18 visx[u] = 1; 19 for(int v = 1; v <= cnty; v++) 20 { 21 if(!visy[v])//还未加入增广路 22 { 23 int t = wx[u] + wy[v] - Map[u][v]; 24 //计算边权和顶标之差,为0表示是相等子图 25 if(t == 0) 26 { 27 visy[v] = 1; 28 if(cy[v] == -1 || dfs(cy[v]))//还未匹配或者反向找到增广路 29 { 30 cy[v] = u; 31 cx[u] = v; 32 //cout<<u<<"v"<<v<<endl; 33 return 1; 34 } 35 } 36 else if(t > 0)minz = min(minz, t); 37 } 38 } 39 return 0; 40 } 41 42 int KM() 43 { 44 memset(cx, -1, sizeof(cx)); 45 memset(cy, -1, sizeof(cy)); 46 memset(wx, -INF, sizeof(wx));//注意,这里存的是负边,所以初始化必须是负无穷 47 memset(wy, 0, sizeof(wy)); 48 for(int i = 1; i <= cntx; i++)//预处理出X部的顶标值 49 { 50 for(int j = 1; j <= cnty; j++) 51 { 52 wx[i] = max(wx[i], Map[i][j]); 53 //cout<<wx[i]<<endl; 54 } 55 } 56 for(int i = 1; i <= cntx; i++) 57 { 58 while(1) 59 { 60 minz = INF; 61 memset(visx, 0, sizeof(visx)); 62 memset(visy, 0, sizeof(visy)); 63 if(dfs(i))break; 64 65 for(int j = 1; j <= cntx; j++) 66 if(visx[j])wx[j] -= minz; 67 for(int j = 1; j <= cnty; j++) 68 if(visy[j])wy[j] += minz; 69 } 70 } 71 int ans = 0; 72 for(int i = 1; i <= cntx; i++) 73 if(cx[i] != -1)ans += Map[i][cx[i]]; 74 return ans; 75 } 76 struct node 77 { 78 int x, y; 79 node(){} 80 node(int x, int y):x(x), y(y){} 81 }; 82 node house[maxx], man[maxy]; 83 char M[105][105]; 84 int main() 85 { 86 int n, m; 87 while(cin >> n >> m && (n && m)) 88 { 89 cntx = cnty = 0; 90 for(int i = 0; i < n; i++)//读图 91 { 92 cin >> M[i]; 93 for(int j = 0; j < m; j++) 94 { 95 if(M[i][j] == \'H\')house[++cntx] = node(i, j); 96 else if(M[i][j] == \'m\')man[++cnty] = node(i, j); 97 } 98 } 99 100 for(int i = 1; i <= cntx; i++)//建图 101 { 102 for(int j = 1; j <= cnty; j++) 103 { 104 Map[i][j] = -abs(house[i].x - man[j].x) - abs(house[i].y - man[j].y); 105 } 106 } 107 cout<<(-KM())<<endl; 108 } 109 return 0; 110 }
以上是关于POJ-2195 Going Home---KM算法求最小权值匹配(存负边)的主要内容,如果未能解决你的问题,请参考以下文章