题目大意:
给你n个房子和n个人,每个人要住一间房子。每个人到房子有一个距离。求所有人都有房子,并且所走的总距离是最小的。
================================================
二分图KM:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> #include<queue> #include<map> using namespace std; typedef long long LL; const int INF = 1e9+7; const int maxn = 105; const int MOD = 1e9+7; struct node { int x, y; node (int x=0,int y=0): x(x), y(y) {} } Man[maxn], House[maxn]; int Lx[maxn], Ly[maxn], G[maxn][maxn], P[maxn], k, d;///可行性顶标 bool vx[maxn], vy[maxn]; char maps[maxn][maxn]; bool Find(int u) { vx[u] = true; for(int i=0; i<k; i++) { if(!vy[i] && Lx[u] + Ly[i] == G[u][i]) { vy[i] = true; if(P[i] == -1 || Find(P[i]) ) { P[i] = u; return true; } } if(!vy[i]) d = min(d, Lx[u] + Ly[i] - G[u][i]); } return false; } int solve() { memset(P, -1, sizeof(P)); for(int i=0; i<k; i++) { while(1) { memset(vx, false, sizeof(vx)); memset(vy, false, sizeof(vy)); d = INF; if( Find(i) ) break; for(int j=0; j<k; j++) { if(vx[j]) Lx[j] -= d; if(vy[j]) Ly[j] += d; } } } int ans = 0; for(int i=0; i<k; i++) ans += G[P[i]][i]; return abs(ans); } int Len(node A, node B) { return abs(A.x - B.x) + abs(A.y - B.y); } int main() { int n, m, k1, k2;///n*m的矩阵有k个房子 while(scanf("%d %d",&n, &m), n+m) { k1 = k2 = 0; memset(Lx, 0, sizeof(Lx)); memset(Ly, 0, sizeof(Ly)); for(int i=0; i<n; i++) { scanf("%s", maps[i]); for(int j=0; j<m; j++) { if(maps[i][j] == 'H') House[k1 ++] = node(i,j); if(maps[i][j] == 'm') Man[k2 ++] = node(i,j); } } k = k1; for(int i=0; i<k; i++) for(int j=0; j<k; j++) G[i][j] = -Len(House[i],Man[j]); int ans = solve(); printf("%d ", ans); } return 0; } /* 5 5 HH..m ..... ..... ..... mm..H */
===========================================================================================================
网络流
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> #include<queue> #include<map> using namespace std; typedef long long LL; const int INF = 1e9+7; const int maxn = 2005; const int MOD = 1e9+7; /**最小费用最大流*/ struct Point { int x, y; Point(int x=0,int y=0): x(x), y(y) {} }Man[maxn], House[maxn]; struct Map { int flow, cost; Map(int flow=0,int cost=0):flow(flow), cost(cost) {} }G[maxn][maxn]; int dist[maxn], Pre[maxn], k; bool vis[maxn]; char maps[maxn][maxn]; int Len(Point A,Point B) { return abs(A.x-B.x) + abs(A.y-B.y); } bool Spfa(int Star,int End) { for(int i=0; i <= End; i++) dist[i] = INF; dist[Star] = 0; memset(Pre, 0, sizeof(Pre)); memset(vis, false, sizeof(vis)); queue<int> Q; Q.push(Star); vis[Star] = true; while(Q.size()) { int u = Q.front(); Q.pop(); vis[u] = false; for(int i=0; i<=End; i++) { if(dist[u]+G[u][i].cost < dist[i] && G[u][i].flow) { Pre[i] = u; dist[i] = dist[u]+G[u][i].cost; if(!vis[i]) { vis[i] = true; Q.push(i); } } } } return dist[End] != INF; } int solve(int Star,int End) { int cost = 0; while( Spfa(Star, End) ) { for(int i=End; i!= Star; i=Pre[i]) { cost += G[Pre[i]][i].cost; G[Pre[i]][i].flow -= 1; G[i][Pre[i]].flow += 1; } } return cost; } int main() { int n, m; while(scanf("%d %d",&n, &m),n+m) { memset(G, 0,sizeof(G)); int k1 = 0, k2 = 0; for(int i=0; i<n; i++) { scanf("%s", maps[i]); for(int j=0; j<m; j++) { if(maps[i][j] == 'H') House[k1++] = Point(i,j); if(maps[i][j] == 'm') Man[k2++] = Point(i,j); } } int Star = 0, End = 2*k1+1; for(int i=1; i<=k1; i++)///建立源点到人的边 G[0][i] = Map(1, 0); for(int i=1; i<=k1; i++)///建立人到房子 for(int j=k1+1; j<=2*k1; j++) { G[i][j] = Map(1, Len(Man[i-1], House[j-k1-1])); G[j][i].cost = -G[i][j].cost; } for(int i=k1+1; i<=2*k1; i++)///建立房子到汇点的边 G[i][End] = Map(1, 0); printf("%d ", solve(Star, End)); } return 0; }