Description:
给出一个矩阵,矩阵中m代表人,H代表房子,房子和人的数量相等,人每次可上下左右移动一格,人的移动互不干扰,问所有的人都进入互不相同不同的房子,所有人最少一共走多少步。
Input:
多组数据
每组第一行是n和m,分别代表矩阵的行数和列数。
之后是个n*m的矩阵。
Output:
每组数据输出一个整数代表最少总步数。
Analysis:
因为人的行动只要不出界是不受到任何限制的,所以只要确定了人与房子的匹配,每个人必然都是以最短路线走入各自房子才能保证步数最小。也即某个人到某个房子所要走的步数对答案的贡献是确定的(|r1-r2|+|c1-c2|),所以问题变为求人与房子的一个完美匹配,使得权和最小。可用KM算法。
更具体来说,KM算法求的是最大权和,所以可以直接把原有的权值取为负值,在最后把答案取反还原。这里相当于把KM算法当做一个黑箱,把输入输出都做一个取反变换从而达到求最小权和的目的。
代码:
#include<iostream> #include<string> #include<cstring> #include<vector> #include<stack> #include<algorithm> #include<map> #include<set> #include<queue> #include<sstream> #include<cmath> #include<iterator> #include<bitset> #include<stdio.h> using namespace std; #define _for(i,a,b) for(int i=(a);i<(b);++i) #define _rep(i,a,b) for(int i=(a);i<=(b);++i) typedef long long LL; int readint() { int x; cin >> x; return x; } const int INF = 1 << 30; const int maxn = 5005; vector<pair<int,int> > px,py; int n,m; int w[maxn][maxn],mint; int vall[maxn],valr[maxn],visl[maxn],visr[maxn],linkl[maxn],linkr[maxn]; bool find(int u){ visl[u]=1; for(int i=0;i<py.size();++i){ if(!visr[i]){ int t=vall[u]+valr[i]-w[u][i]; if(t==0){ visr[i]=1; if(linkr[i]==-1||find(linkr[i])){ linkl[u]=i;linkr[i]=u; return true; } } else mint=min(mint,t); } } return false; } int KM(){ memset(linkl,-1,sizeof(linkl)); memset(linkr,-1,sizeof(linkr)); for(int i=0;i<px.size();++i){ while(1){ memset(visl,0,sizeof(visl)); memset(visr,0,sizeof(visr)); mint=INF; if(find(i))break; for(int j=0;j<px.size();++j) if(visl[j])vall[j]-=mint; for(int j=0;j<py.size();++j) if(visr[j])valr[j]+=mint; } } int ans=0; for(int i=0;i<px.size();++i){ ans+=w[i][linkl[i]]; } return ans; } int main() { //freopen("C:\\Users\\admin\\Desktop\\in.txt", "r", stdin); //freopen("C:\\Users\\admin\\Desktop\\out.txt", "w", stdout); while(~scanf("%d%d",&n,&m)){ if(n==0&&m==0)break; string s;px.clear(),py.clear(); for(int i=0;i<n;++i){ cin>>s; for(int j=0;j<m;++j){ if(s[j]=='m'){ px.push_back({i,j}); } else if(s[j]=='H'){ py.push_back({i,j}); } } } memset(vall,0,sizeof(vall)); memset(valr,0,sizeof(valr)); for(int i=0;i<px.size();++i) for(int j=0;j<py.size();++j){ w[i][j]=-(abs(px[i].first-py[j].first)+abs(px[i].second-py[j].second)); vall[i]=max(vall[i],w[i][j]); } printf("%d\n",-KM()); } return 0; }