Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 2963 Accepted Submission(s): 1492
2 2 .m H. 5 5 HH..m ..... ..... ..... mm..H 7 8 ...H.... ...H.... ...H.... mmmHmmmm ...H.... ...H.... ...H.... 0 0
2 10 28
解题思路:
题意为n*m的方格中有p个房子和p个人,人每走一步花费1美元,要求每个人都要找到一个房子,且每个房子里只能有一个人,问p个人都找到各自的房子,最小的花费是多少。
可以用KM算法求出最大的花费,要求最小花费只要把邻接矩阵中的权值取反,然后用Km算法最后返回 最大值的相反数就是要求的最小花费。
代码:
#include <iostream> #include <string.h> #include <cmath> #include <algorithm> using namespace std; const int maxn=102; const int inf=0x3f3f3f3f; char mp[maxn][maxn]; int n,m; int npeople; int g[maxn][maxn]; int nx,ny; int linked[maxn],lx[maxn],ly[maxn]; int slack[maxn]; bool visx[maxn],visy[maxn]; struct House//存放房子的坐标 { int x,y; }house[maxn]; struct Man//存放人的坐标 { int x,y; }man[maxn]; bool DFS(int x)//hungary { visx[x]=true; for(int y=0;y<ny;y++) { if(visy[y]) continue; int tmp=lx[x]+ly[y]-g[x][y]; if(tmp==0) { visy[y]=true; if(linked[y]==-1||DFS(linked[y])) { linked[y]=x; return true; } } else if(slack[y]>tmp) slack[y]=tmp; } return false; } int KM() { memset(linked,-1,sizeof(linked)); memset(ly,0,sizeof(ly)); for(int i=0;i<nx;i++) { lx[i]=-inf; for(int j=0;j<ny;j++) if(g[i][j]>lx[i]) lx[i]=g[i][j]; } for(int x=0;x<nx;x++) { for(int i=0;i<ny;i++) slack[i]=inf; while(true) { memset(visx,0,sizeof(visx)); memset(visy,0,sizeof(visy)); if(DFS(x)) break; int d=inf; for(int i=0;i<ny;i++) if(!visy[i]&&d>slack[i]) d=slack[i]; for(int i=0;i<nx;i++) if(visx[i]) lx[i]-=d; for(int i=0;i<ny;i++) { if(visy[i]) ly[i]+=d; else slack[i]-=d; } } } int ans=0; for(int i=0;i<ny;i++) if(linked[i]!=-1) ans+=g[linked[i]][i]; return -ans;//返回最大的相反数,即要求的最小 } int main() { while(cin>>n>>m&&(n||m)) { int h1=-1,m1=-1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { cin>>mp[i][j]; if(mp[i][j]=='H') house[++h1].x=i,house[h1].y=j; else if(mp[i][j]=='m') man[++m1].x=i,man[m1].y=j; } npeople=(++h1); memset(g,inf,sizeof(g)); for(int i=0;i<npeople;i++)//计算邻接矩阵 for(int j=0;j<npeople;j++) { int dist=abs(man[i].x-house[j].x)+abs(man[i].y-house[j].y); g[i][j]=-dist;//权值取反 } nx=ny=npeople; cout<<KM()<<endl; } return 0; }
[ACM] HDU 1533 Going Home (二分图最小权匹配,KM算法)
原文:http://blog.csdn.net/sr_19930829/article/details/40660303