链接:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=82835#problem/D
有n个人有n栋房子,每栋房子里能进一个人,但每走一格的价值是1, 所以要尽可能的少走,这一看很显然是匹配用KM算法,
但这是网络流专题的,不是太懂怎么用网络流来写
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> using namespace std; #define N 110 #define INF 0x3fffffff struct node{int x, y, step;}; char G[N][N]; int n, m1, dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; int STEP[N][N], m[N][N], H[N][N], vis[N][N]; int num1, num2, lx[N], ly[N]; int used[N], visx[N], visy[N], s[N]; void BFS(node p) { node q, t; queue<node>Q; Q.push(p); memset(vis, 0, sizeof(vis)); vis[p.x][p.y] = 1; while(Q.size()) { q = Q.front(); Q.pop(); if(G[q.x][q.y]=='H') STEP[m[p.x][p.y]][H[q.x][q.y]] = -q.step; for(int i=0; i<4; i++) { t.x = q.x + dir[i][0]; t.y = q.y + dir[i][1]; t.step = q.step + 1; if(t.x>=0 && t.x<n && t.y>=0 && t.y<m1 && !vis[t.x][t.y]) { Q.push(t); vis[t.x][t.y] = 1; } } } } bool Find(int u) { visx[u] = 1; for(int i=1; i<=num2; i++) { if(!visy[i] && lx[u]+ly[i]==STEP[u][i]) { visy[i] = 1; if(!used[i] || Find(used[i])) { used[i] = u; return true; } } else s[i] = min(s[i], lx[u]+ly[i]-STEP[u][i]); } return false; } void KM() { memset(used, 0, sizeof(used)); memset(lx, 0, sizeof(lx)); memset(ly, 0, sizeof(ly)); for(int i=1; i<=num1; i++) for(int j=1; j<=num2; j++) lx[i] = max(lx[i], STEP[i][j]); for(int i=1; i<=num1; i++) { for(int j=1; j<=num2; j++) s[j] = INF; while(1) { memset(visx, 0, sizeof(visx)); memset(visy, 0, sizeof(visy)); if(Find(i)) break; int d = INF; for(int j=1; j<=num2; j++) if(!visy[j]) d = min(d, s[j]); for(int j=1; j<=num2; j++) { if(visx[j]) lx[j] -= d; if(visy[j]) ly[j] += d; } } } int res = 0; for(int i=1; i<=num1; i++) res -= STEP[used[i]][i]; printf("%d\n", res); } int main() { while(scanf("%d%d", &n, &m1), n+m1) { int i, j; node p; num1=0, num2=0; memset(STEP, 0, sizeof(STEP)); for(i=0; i<n; i++) { scanf("%s", G[i]); for(j=0; j<m1; j++) { if(G[i][j]=='m') m[i][j] = ++num1; if(G[i][j]=='H') H[i][j] = ++num2; } } for(i=0; i<n; i++) for(j=0; j<m1; j++) { if(G[i][j]=='m') { p.x=i, p.y=j, p.step=0; BFS(p); } } KM(); } return 0; }
粘个别人的代码:
#include<stdio.h> #include<string.h> #include<queue> #include<stack> #include<algorithm> #include<math.h> using namespace std; const int MAXN = 407; const int oo = 1e9+7; struct point{int x, y;}man[MAXN], house[MAXN]; struct Graph{int flow, cost;}G[MAXN][MAXN]; int NX, NY, start, End;///男人和房子的数目,源点和汇点 bool spfa(int pre[]) { stack<int> sta; int instack[MAXN]={0}, dist[MAXN]; for(int i=1; i<=End; i++) dist[i] = oo; dist[start] = 0; sta.push(start); while(sta.size()) { int u = sta.top();sta.pop(); instack[u] = false; for(int i=1; i<=End; i++) { if(G[u][i].flow && dist[i] > dist[u]+G[u][i].cost) { dist[i] = dist[u] + G[u][i].cost; pre[i] = u; if(instack[i] == false) { sta.push(i); instack[i] = true; } } } } return dist[End] != oo; } int MinCost() { int i, pre[MAXN], cost=0; while(spfa(pre) == true) {///如果有增广路 int MinFlow = oo; for(i=End; i != start; i=pre[i]) MinFlow = min(MinFlow, G[pre[i]][i].flow); for(i=End; i != start; i=pre[i]) {///逆向访问这条增广路上的每条边 int k = pre[i]; G[k][i].flow -= MinFlow; G[i][k].flow += MinFlow; cost += G[k][i].cost; } } return cost; } int main() { int M, N; while(scanf("%d%d", &M, &N), M+N) { int i, j;char s[MAXN][MAXN]; memset(G, 0, sizeof(G)); NX = NY = 0; for(i=0; i<M; i++) scanf("%s", s[i]); for(i=0; i<M; i++) for(j=0; j<N; j++) { if(s[i][j] == 'm') { NX++; man[NX].x = i; man[NX].y = j; } if(s[i][j] == 'H') { NY++; house[NY].x = i; house[NY].y = j; } } for(i=1; i<=NX; i++) for(j=1; j<=NY; j++) {///房子的编号从NX~NX+NY G[i][NX+j].flow = 1; G[i][NX+j].cost = fabs(man[i].x-house[j].x)+fabs(man[i].y-house[j].y); G[NX+j][i].cost = -G[i][NX+j].cost; } start = NX+NY+1, End = start+1; for(i=1; i<=NX; i++) {///把源点与人连接 G[start][i].flow = 1; G[start][i].cost = 0; } for(i=1; i<=NY; i++) {///把房子和汇点连接 G[NX+i][End].flow = 1; G[NX+i][End].cost = 0; } printf("%d\n", MinCost()); } return 0; }
勿忘初心