• 题意
    • 给a*b大小的栅格
    • 其中.代表空,m代表人,H代表房子,每座房子只能容纳一个人,人可以水平或竖直地经过任意栅格到达一座房子,每经过一个栅格,花费为1
    • 在最多人能到一所房子的情况下,求最小花费
  • 题解
    • 显然是最小费用最大流问题
    • 直接将源点连向人, 费用0,流量1
    • 将房子连向汇点,费用0,流量1
    • 将人连向房子,费用为人和房子之间的曼哈顿距离,流量为1
    • 跑一个最小费用最大流即可
  • 代码
    • //#include<bits/stdc++.h>
      #include<algorithm>
      #include <iostream>
      #include   <fstream>
      #include  <cstdlib>
      #include  <cstring>
      #include  <cassert>
      #include   <cstdio>
      #include   <vector>
      #include   <string>
      #include    <cmath>
      #include    <queue>
      #include    <stack>
      #include      <set>
      #include      <map>
      using namespace std;
      #define P(a,b,c) make_pair(a,make_pair(b,c))
      #define rep(i,a,n) for (int i=a;i<=n;i++)
      #define per(i,a,n) for (int i=n;i>=a;i--)
      #define CLR(vis) memset(vis,0,sizeof(vis))
      #define MST(vis,pos) memset(vis,pos,sizeof(vis))
      #define pb push_back
      #define mp make_pair
      #define all(x) (x).begin(),(x).end()
      #define fi first
      #define se second
      #define SZ(x) ((int)(x).size())
      typedef pair<int,pair<int,int> >pii;
      typedef long long ll;
      typedef unsigned long long ull;
      const ll mod = 1000000007;
      ll gcd(ll a, ll b) {
      	return b ? gcd(b, a%b) : a;
      }
      template<class T>inline void gmax(T &A, T B) {
      	(A<B)&&(A=B);//if(B>A)A=B;
      }
      template<class T>inline void gmin(T &A, T B) {
      	(A>B)&&(A=B);//if(B<A)A=B;
      }
      template <class T>
      inline bool scan_d(T &ret) {
      	char c;
      	int sgn;
      	if(c=getchar(),c==EOF) return 0; //EOF
      	while(c!='-'&&(c<'0'||c>'9')) c=getchar();
      	sgn=(c=='-')?-1:1;
      	ret=(c=='-')?0:(c-'0');
      	while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
      	ret*=sgn;
      	return 1;
      }
      inline void outt(int x) {
      	if(x>9) outt(x/10);
      	putchar(x%10+'0');
      }
      const int MX = 505;
      const int inf = 0x3f3f3f3f;
      const int MXE = MX * MX * 4;
      struct MinCost_MaxFlow {
          struct Edge {
              int v, w, nxt;
              int cost;
          } E[MXE];
          int head[MX], tot, level[MX], pre[MX], d[MX];
          bool vis[MX];
          void init() {
              memset(head, -1, sizeof(head));
              tot = 0;
          }
          void add(int u, int v, int w, int cost) {
              E[tot].v = v;
              E[tot].w = w;
              E[tot].cost = cost;
              E[tot].nxt = head[u];
              head[u] = tot++;
              E[tot].v = u;
              E[tot].w = 0;
              E[tot].cost = -cost;
              E[tot].nxt = head[v];
              head[v] = tot++;
          }
          bool spfa(int s, int t) {
              memset(vis, 0, sizeof(vis));
              memset(d, 0x3f, sizeof(d));
              memset(pre, -1, sizeof(pre));
              queue<int>q;
              q.push(s);
              d[s] = 0;
              vis[s] = 1;
              while (!q.empty()) {
                  int u = q.front();
                  q.pop();
                  vis[u] = 0;
                  for (int i = head[u]; ~i; i = E[i].nxt) {
                      int w = E[i].w, v = E[i].v, cost = E[i].cost;
                      if (w > 0 && d[v] > d[u] + cost) {
                          d[v] = d[u] + cost;
                          pre[v] = i;
                          if (!vis[v]) {
                              q.push(v);
                              vis[v] = 1;
                          }
                      }
                  }
              }
              //如果是最小费用可行流则要这一句(要求费用最小,不要求流量最大)
              //if (d[t] > 0) return false;
              return pre[t] != -1;
          }
          int solve(int s, int t, int &cost) {
              int flow = 0;
              cost = 0;
              while (spfa(s, t)) {
                  int minFlow = inf;
                  for (int i = pre[t]; ~i; i = pre[E[i ^ 1].v])
                      minFlow = min(minFlow, E[i].w);
                  for (int i = pre[t]; ~i; i = pre[E[i ^ 1].v]) {
                      cost += minFlow * E[i].cost;
                      E[i].w -= minFlow;
                      E[i ^ 1].w += minFlow;
                  }
                  flow += minFlow;
              }
              return flow;
          }
      } F;
      int n, m;
      struct  Point {
          int x, y;
          Point (int x, int y): x(x), y(y) {}
      };
      int cal(Point a, Point b) {
          return abs(a.x - b.x) + abs(a.y - b.y);
      }
      char tu[105][105];
      vector<Point>men;
      vector<Point>home;
      int main() {
          while(~scanf("%d%d", &n, &m), n + m) {
              F.init();
              men.clear();
              home.clear();
              for (int i = 0 ; i < n ; i++) {
                  scanf("%s", tu[i]);
                  for (int j = 0 ; j < m ; j++) {
                      if (tu[i][j] == 'm') men.push_back(Point(i, j));
                      if (tu[i][j] == 'H') home.push_back(Point(i, j));
                  }
              }
              int s=0,len1=men.size(),len2=home.size(),t;
              t=len1+len2+1;
              for (int i=0 ;i<len1 ;i++)
                  for (int j=0 ;j<len2 ;j++)
                      F.add(i+1,j+1+len1,1,cal(men[i],home[j]));
              for (int i=1 ;i<=len1 ;i++) F.add(0,i,1,0);
              for (int i=1 ;i<=len2 ;i++) F.add(i+len1,t,1,0);
              int cost = 0;
              F.solve(s, t, cost);
              printf("%d\n", cost);
          }
          return 0;
      }

发表评论

邮箱地址不会被公开。 必填项已用*标注