题目链接:Going Home
解题思路:最小费用最大流的问题,建图的时候要有超级源点和超级汇点,源点连接所有的小孩,花费为0,容量为1,所有的房子连接超级汇点,花费和容量与上边相同。然后每个孩子和每个房子连接一条路径,花费为两点距离 abs(x1 - x2)+ abs(y1 - y2),容量为1。在原图的基础上面建立花费图,如果两点的正向边的容量不为0的话那么就为w,反向变不为0的话就为-w。
算法的核心思想就是通过寻找花费图源点到汇点的最短路径。这个路径就是增广1单位容量花费的钱数。如果最后不存在最短路径的话说明汇点已经达到最大流。
#include<stdio.h> #include<string.h> #include<queue> #include<stdlib.h> #include<vector> #define MAXN 5000 #define MAXM 50000 #define INF 0x3f3f3f3f using namespace std; typedef struct A{ int x, y; A(){} A(int a, int b){ x = a, y = b; } }node; typedef struct B{ int e, c, v, nxt; B(){} B(int a, int b, int q, int d){ e = a, c = b, v = q, nxt = d; } }edge; bool vis[MAXN]; edge Map[MAXM]; int g[MAXN]; int dis[MAXN]; int pree[MAXN], prev[MAXN]; vector<node> mm, hh; int tot = 2, n, m; int minNum(int a, int b){ return a < b ? a : b; } void addedge(int u, int v, int c, int w){ Map[tot] = edge(v, c, w, g[u]); g[u] = tot++; Map[tot] = edge(u, 0, -1 * w, g[v]); g[v] = tot++; } void init(){ mm.clear(); hh.clear(); tot = 2; memset(g, 0, sizeof(g)); memset(Map, 0, sizeof(Map)); memset(pree, 0, sizeof(pree)); memset(prev, 0, sizeof(prev)); } bool spfa(){ int i, j, sink = mm.size() * 2 + 1; queue<int> que; memset(vis, false, sizeof(vis)); memset(dis, 127, sizeof(dis)); que.push(0); dis[0] = 0; vis[0] = true; while(!que.empty()){ int s = que.front(); que.pop(); for(i = g[s]; i; i = Map[i].nxt){ if(Map[i].c && dis[Map[i].e] > dis[s] + Map[i].v){ dis[Map[i].e] = dis[s] + Map[i].v; pree[Map[i].e] = i; prev[Map[i].e] = s; if(!vis[Map[i].e]){ que.push(Map[i].e); vis[Map[i].e] = true; } } } vis[s] = false; } if(dis[sink] < INF){ return true; } return false; } int slove(){ int u = mm.size() * 2 + 1; int detla = INF; while(u != 0){ if(Map[pree[u]].c < detla){ detla = Map[pree[u]].c; } u = prev[u]; } u = mm.size() * 2 + 1; while(u != 0){ Map[pree[u]].c -= detla; Map[pree[u] ^ 1].c += detla; u = prev[u]; } return dis[mm.size() * 2 + 1] * detla; } int mincostflow(){ int ret = 0; while(spfa()){ ret += slove(); } return ret; } int main(){ int i, j, k; char p; // freopen("in.txt", "r", stdin); while(scanf("%d%d", &n, &m) && (n || m)){ init(); for(i = 0; i < n; i++){ getchar(); for(j = 0; j < m; j++){ scanf("%c", &p); if(p == 'H'){ hh.push_back(node(i, j)); } if(p == 'm'){ mm.push_back(node(i, j)); } } }/* for(i = 0; i < hh.size(); i++){ printf("%d %d ------%d %d\n", hh[i].x, hh[i].y, mm[i].x, mm[i].y); }*/ for(i = 0; i < mm.size(); i++){ addedge(0, i + 1, 1, 0); addedge(i + 1 + mm.size(), mm.size() * 2 + 1, 1, 0); for(j = 0; j < hh.size(); j++){ addedge(i + 1, j + 1 + hh.size(), 1, abs(mm[i].x - hh[j].x) + abs(mm[i].y - hh[j].y)); } } printf("%d\n", mincostflow()); } return 0; }