(说明:这个专题中有很多题目也可以运用KM匹配算法。)
HDU 1533 Going Home
入门题,典型二分图最优权值匹配。
建图:
1. 超级源点与人连边,流量为1,花费为0;
2. 房子与超级汇点连边,流量为1,花费为0;
3. 每个人与每个房子连边,流量为1,花费为距离。
#include <vector> #include <list> #include <map> #include <set> #include <queue> #include <deque> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <cstring> #include <ctime> #include <queue> #include <cassert> using namespace std; #define MP make_pair #define PB push_back #define F first #define S second #define pii pair<int,int> #define clr(a) memset((a),0,sizeof (a)) #define rep(i,a,b) for(int i=(a);i<=(int)(b);i++) #define per(i,a,b) for(int i=(a);i>=(int)(b);i--) #define inf (0x3f3f3f3f) #define eps 1e-6 #define MAXN 505 #define MAXM 4000005 #define MODN 1000000007 #define RI(x) scanf("%d", &x) #define RII(x,y) scanf("%d%d", &x, &y) #define RIII(x,y,z) scanf("%d%d%d", &x, &y, &z) #define debug puts("reach here"); typedef long long LL; struct Edge { int to; int vol; int cost; int next; }E[MAXM]; int index[MAXN]; int NE; int pre[MAXN], pos[MAXN]; int dis[MAXN], que[MAXM]; bool vis[MAXN]; int n, m, k; char g[105][105]; vector<pii> vm, vh; void add_edge(int from, int to, int vol, int cost) { E[NE].to = to; E[NE].vol = vol; E[NE].cost = cost; E[NE].next = index[from]; index[from] = NE++; E[NE].to = from; E[NE].vol = 0; E[NE].cost = -cost; E[NE].next = index[to]; index[to] = NE++; } bool spfa(int s, int t) { memset(pre, -1, sizeof(pre)); memset(vis, 0, sizeof(vis)); int head, tail; head = tail = 0; memset(dis, 0x3f, sizeof dis); que[tail++] = s; pre[s] = s; dis[s] = 0; vis[s] = 1; while(head != tail) { int cur = que[head++]; vis[cur] = 0; for(int i = index[cur]; i != -1; i = E[i].next) { int adj = E[i].to; if(E[i].vol > 0 && dis[cur] + E[i].cost < dis[adj]) { dis[adj] = dis[cur] + E[i].cost; pre[adj] = cur; pos[adj] = i; if(!vis[adj]) { vis[adj] = 1; que[tail++] = adj; } } } } return pre[t] != -1; } int MinCostMaxFlow(int s, int t) { int cost = 0; int flow = 0; while(spfa(s, t)) { int f = inf; for(int i = t; i != s; i = pre[i]) if (E[pos[i]].vol < f) f = E[pos[i]].vol; flow += f; cost += dis[t] * f; for(int i = t; i != s; i = pre[i]) { E[pos[i]].vol -= f; E[pos[i] ^ 1].vol += f; } } return cost; } void init() { NE = 0; memset(index, -1, sizeof index); } int main() { while(RII(n, m) != EOF) { if(n == 0 && m == 0) break; vm.clear(); vh.clear(); rep(i,0,n-1) { scanf("%s", g[i]); rep(j,0,m-1) if(g[i][j] == 'm') vm.PB(MP(i,j)); else if(g[i][j] == 'H') vh.PB(MP(i,j)); } int s = 0, t = vm.size() + vh.size() + 1; int m = vm.size(); init(); rep(i,0,m-1) { add_edge(0, 1+i, 1, 0); rep(j,0,vh.size()-1) add_edge(1+i, 1+m+j, 1, abs(vm[i].F - vh[j].F)+abs(vm[i].S-vh[j].S)); } rep(j,0,vh.size()-1) add_edge(1+m+j, t, 1, 0); printf("%d\n", MinCostMaxFlow(s,t)); } }