POJ 2195 二分圖帶權完美匹配
阿新 • • 發佈:2018-12-24
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; }