HDU-2195-Going Home
http://acm.hdu.edu.cn/showproblem.php?pid=1533
之前用最小费用最大流做的,今天看了最大带权匹配的KM算法,套用了模板来做这题,将所有的H作为X集合,所有的m作为Y集合,构造二分图求最大带权匹配
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> using namespace std; const int MAXN=5000; const int INF=0x7fffffff; int nx, ny, w[MAXN][MAXN], lx[MAXN], ly[MAXN]; int fx[MAXN], fy[MAXN], matx[MAXN], maty[MAXN]; char map[MAXN][MAXN]; int n1,n2; struct node { int x; int y; }h[MAXN],man[MAXN]; //模板 // Name: PerfectMatch by Kuhn_Munkras O(n^3) // Description: w is the adjacency matrix, nx,ny are the size of x and y, // lx, ly are the lables of x and y, fx[i], fy[i] is used for marking // whether the i-th node is visited, matx[x] means x match matx[x], // maty[y] means y match maty[y], actually, matx[x] is useless, // all the arrays are start at 1 int path(int u) { fx[u] = 1; for (int v = 1; v <= ny; v++) if (lx[u] + ly[v] == w[u][v] && fy[v] < 0) { fy[v] = 1; if (maty[v] < 0 || path(maty[v])) { matx[u] = v; maty[v] = u; return 1; } } return 0; } int km() { int i,j,k,ret = 0; memset(ly, 0, sizeof(ly)); for (i = 1; i <= nx; i++) { lx[i] = -INF; for (j = 1; j <= ny; j++) if (w[i][j] > lx[i]) lx[i] = w[i][j]; } memset(matx, -1, sizeof(matx)); memset(maty, -1, sizeof(maty)); for (i = 1; i <= nx; i++) { memset(fx, -1, sizeof(fx)); memset(fy, -1, sizeof(fy)); if (!path(i)) { i--; int p = INF; for (k = 1; k <= nx; k++) { if (fx[k] > 0) for (j = 1; j <= ny; j++) if (fy[j] < 0 && lx[k] + ly[j] - w[k][j] < p) p=lx[k]+ly[j]-w[k][j]; } for (j = 1; j <= ny; j++) ly[j] += fy[j]<0 ? 0 : p; for (j = 1; j <= nx; j++) lx[j] -= fx[j]<0 ? 0 : p; } } for (i = 1; i <= ny; i++) ret += w[maty[i]][i]; return ret; } void init() { int i,j,v; char c; nx=ny=0; for(i=0;i<n1;i++) { for(j=0;j<n2;j++) { scanf("%c",&c); if(c=='H') { h[++nx].x=i; h[nx].y=j; } else if(c=='m') { man[++ny].x=i; man[ny].y=j; } } getchar(); } for(i=1;i<=nx;i++) for(j=1;j<=ny;j++) w[i][j]=-99999999; for(i=1;i<=nx;i++) for(j=1;j<=ny;j++) w[i][j]=-(abs(h[i].x-man[j].x)+abs(h[i].y-man[j].y)); } int main() { while(scanf("%d %d",&n1,&n2),n1||n2) { getchar(); init(); printf("%d\n",-km()); } return 0; }