最大权匹配: 在一个二分图内,左顶点为X,右顶点为Y,现对于每组左右连接XiYj有权wij,求一种匹配使得所有wij的和最大。
用KM算法解决
- #include <iostream>
- #include <cmath>
- #include <vector>
- #include <cstdlib>
- #include <cstdio>
- #include <cstring>
- #include <queue>
- #include <list>
- #include <algorithm>
- #include <map>
- #include <set>
- #define LL long long
- #define fread() freopen("in.in","r",stdin)
- #define fwrite() freopen("out.out","w",stdout)
- #define Pr pair<int,int>
- using namespace std;
- const int INF = 0x3f3f3f3f;
- const int msz = 10000;
- const double eps = 1e-8;
- //二分图
- int mp[233][233];
- // x顶标 y顶标
- int lx[233],ly[233],link[233],slick[233];
- bool visx[233],visy[233];
- // 人的坐标 房子坐标
- Pr human[233],house[233];
- //人数 房数
- int nm,nh;
- bool cal(int x)
- {
- visx[x] = 1;
- for(int y = 0; y < nh; ++y)
- {
- if(visy[y]) continue;
- int t = lx[x]+ly[y]-mp[x][y];
- if(t == 0)
- {
- visy[y] = 1;
- if(link[y] == -1 || cal(link[y]))
- {
- link[y] = x;
- return true;
- }
- }
- else slick[y] = min(slick[y],t);
- }
- return false;
- }
- int KM()
- {
- memset(link,-1,sizeof(link));
- for(int i = 0; i < nm; ++i)
- {
- memset(slick,INF,sizeof(slick));
- while(1)
- {
- memset(visx,0,sizeof(visx));
- memset(visy,0,sizeof(visy));
- if(cal(i)) break;
- int d = INF;
- for(int j = 0; j < nh; ++j)
- if(!visy[j]) d = min(d,slick[j]);
- for(int j = 0; j < nm; ++j)
- if(visx[j]) lx[j] -= d;
- for(int j = 0; j < nh; ++j)
- if(visy[j]) ly[j] += d;
- else slick[j] -= d;
- }
- }
- int ans = 0;
- for(int i = 0; i < nh; ++i)
- if(link[i] != -1) ans += mp[link[i]][i];
- return ans;
- }
- int main()
- {
- int n,m;
- char tmp[233];
- while(~scanf("%d%d",&n,&m) && (n+m))
- {
- nm = nh = 0;
- for(int i = 0; i < n; ++i)
- {
- scanf("%s",tmp);
- for(int j = 0; j < m; ++j)
- if(tmp[j] == 'm') human[nm++] = Pr(i,j);
- else if(tmp[j] == 'H') house[nh++] = Pr(i,j);
- }
- memset(lx,0,sizeof(lx));
- memset(ly,0,sizeof(ly));
- for(int i = 0; i < nm; ++i)
- for(int j = 0; j < nh; ++j)
- {
- mp[i][j] = -(abs(human[i].first-house[j].first)+abs(human[i].second-house[j].second));
- lx[i] = max(lx[i],mp[i][j]);
- }
- printf("%d\n",-KM());
- }
- return 0;
- }
-