POJ 2195 http://acm.pku.edu.cn/JudgeOnline/problem?id=2195 第一道二分图最佳匹配题,简单题,会二分最佳的这题也就会。就建图的时候要把距离算出来! #include <iostream> #include <cmath> using namespace std; int n,m; int num1,num2; char map[150][150]; //初始输入 int mat[150][150]; //记录距离 int house[150][2]; //房子坐标 int man[150][2]; //人的坐标 int pl[150],pr[150]; //左右顶标 int visl[150],visr[150]; //是否被访问 int match[150]; //匹配 int stack[150]; int Min(int a,int b) { return a>b?b:a; } bool find(int a) // 找增广路径 { int i; visl[a] = 1; for(i=0;i<num2;i++) { if(visr[i] == 0) { int val = pl[a] + pr[i] - mat[a][i]; if(val == 0) { visr[i] = 1; if(match[i] == -1 || find(match[i])) { match[i] = a; return 1; } } else { if(val < stack[i]) stack[i] = val; } } } return 0; } int km() { int i,j,k; //初始化顶标 for(i=0;i<num1;i++) { pl[i] = -0x7ffffff; pr[i] = 0; for(j=0;j<num2;j++) { if(mat[i][j] > pl[i]) pl[i] = mat[i][j]; } } memset(match,-1,sizeof(match)); for(k=0;k<num1;k++) { for(i=0;i<150;i++) stack[i] = 0x7fffffff; while(1) { memset(visl,0,sizeof(visl)); memset(visr,0,sizeof(visr)); if(find(k)) break; int d = 0x7ffffff; for(j=0;j<num2;j++) { if(!visr[j]) d = Min(stack[j] , d); } for(i=0;i<num1;i++) { if(visl[i]) pl[i] -= d; if(visr[i]) pr[i] += d; } } } int sum = 0; for(i=0;i<num1;i++) { sum += -1 * mat[match[i]][i]; } return sum; } void Init() { int i,j; num1 = 0; //房子个数 num2 = 0; //人的个数 for(i=0;i<n;i++) { cin>>map[i]; for(j=0;j<m;j++) { if(map[i][j] == 'H') { house[num1][0] = i; house[num1++][1] = j; } if(map[i][j] == 'm') { man[num2][0] = i; man[num2++][1] = j; } } } for(i=0;i<num1;i++) { for(j=0;j<num2;j++) { mat[i][j] = abs(house[i][0] - man[j][0]) + abs(house[i][1] - man[j][1]); mat[i][j] = - mat[i][j]; //因为是取最小权值,所以取反 } } } int main() { while(scanf("%d%d",&n,&m)!=EOF && (n!=0 || m!=0)) { Init(); printf("%d/n",km()); } return 0; }