Pacific Northwest 2004
题意:人回房子,每走一步花费1,问令所有人回到房子的最小花费。 思路:最小费用流,源点->人->房子->汇点建图,所谓最小费用最大流,就是类似最大流的EK算法,不过增广路不是胡乱找,而是在最短路上找,于是得结合spfa或者dijk搞,同时这题有比费用流更高效的做法。
# include <iostream> # include <cstdio> # include <cstring> # include <vector> # include <algorithm> using namespace std; const int maxn = 2e4+100; const int INF = 0x3f3f3f3f; char s[103][103]; int cnt=0, Next[maxn], dis[maxn], vis[maxn], pre[maxn], q[maxn]; vector<pair<int, int> >v1,v2; struct node { int u, v, w, c, next; node(){} node(int u, int v, int w, int c, int next):u(u),v(v),w(w),c(c),next(next){} }edge[maxn<<1]; void add_edge(int u, int v, int w, int c) { edge[cnt] = node(u,v,w,c,Next[u]); Next[u] = cnt++; edge[cnt] = node(v,u,0,-c,Next[v]); Next[v] = cnt++; } bool spfa() { memset(vis, 0, sizeof(vis)); memset(dis, INF, sizeof(dis)); int l=0, r=0; dis[0] = 0; vis[0] = 1; q[r++] = 0; while(l<r) { int u=q[l]; ++l; vis[u] = 0; for(int i=Next[u]; i!=-1; i=edge[i].next) { int v=edge[i].v, w=edge[i].w, c=edge[i].c; if(w>0 && dis[v] > dis[u]+c) { dis[v] = dis[u] + c; pre[v] = i; if(!vis[v]) { q[r++] = v; vis[v] = 1; } } } } return dis[20088] != INF; } int mcmf() { int cost = 0; while(spfa()) { int imin = INF; for(int i=20088; i!=0; i=edge[pre[i]].u) imin = min(imin, edge[pre[i]].w); for(int i=20088; i!=0; i=edge[pre[i]].u) { edge[pre[i]].w -= imin; edge[pre[i]^1].w += imin; } cost += imin*dis[20088]; } return cost; } int main() { int n, m; while(~scanf("%d%d",&n,&m),n+m) { cnt = 0; v1.clear(); v2.clear(); memset(Next, -1, sizeof(Next)); for(int i=1; i<=n; ++i) scanf("%s",s[i]+1); for(int i=1; i<=n; ++i) { for(int j=1; j<=m; ++j) { if(s[i][j] == 'm') v1.push_back(make_pair(i,j)); else if(s[i][j] == 'H') v2.push_back(make_pair(i,j)); } } for(int i=0; i<v1.size(); ++i) { int x1 = v1[i].first, y1 = v1[i].second; add_edge(0, i+1, 1, 0); for(int j=0; j<v2.size(); ++j) { int x2 = v2[j].first, y2 = v2[j].second; add_edge(i+1, j+1+v1.size(), 1, abs(x2-x1)+abs(y2-y1)); } } for(int i=0; i<v2.size(); ++i) { int x1 = v2[i].first, y1 = v2[i].second; add_edge(i+1+v1.size(), 20088, 1, 0); } printf("%d\n",mcmf()); } return 0; }