题意:给一个n*m的地图,'m'表示人,'H'表示房子,求所有人都回到房子所走的距离之和的最小值(距离为曼哈顿距离)。

思路:比较明显的二分图最大权匹配模型,将每个人向房子连一条边,边权为曼哈顿距离的相反数(由于是求最小,所以先取反后求最大,最后再取反回来即可),然后用KM算法跑一遍然后取反就是答案。还可以用最小费用最大流做,方法是:从源点向每个人连一条边,容量为1,费用为0,从每个房子向汇点连一条边,容量为1,费用为0,从每个人向每个房子连一条边,容量为1,费用为曼哈顿距离的值,建好图后跑一遍最小费用最大流就是答案。

附上代码:(1)KM算法,40ms左右 (2)最小费用最大流,400+ms

(1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* ******************************************************************************** */
#include <iostream>                                                                 //
#include <cstdio>                                                                   //
#include <cmath>                                                                    //
#include <cstdlib>                                                                  //
#include <cstring>                                                                  //
#include <vector>                                                                   //
#include <ctime>                                                                    //
#include <deque>                                                                    //
#include <queue>                                                                    //
#include <algorithm>                                                                //
#include <map>                                                                      //
#include <cmath>                                                                    //
using namespace std;                                                                //
                                                                                    //
#define pb push_back                                                                //
#define mp make_pair                                                                //
#define X first                                                                     //
#define Y second                                                                    //
#define all(a) (a).begin(), (a).end()                                               //
#define fillchar(a, x) memset(a, x, sizeof(a))                                      //
                                                                                    //
void RI(vector<int>&a,int n){a.resize(n);for(int i=0;i<n;i++)scanf("%d",&a[i]);}    //
void RI(){}void RI(int&X){scanf("%d",&X);}template<typename...R>                    //
void RI(int&f,R&...r){RI(f);RI(r...);}void RI(int*p,int*q){int d=p<q?1:-1;          //
while(p!=q){scanf("%d",p);p+=d;}}void print(){cout<<endl;}template<typename T>      //
void print(const T t){cout<<t<<endl;}template<typename F,typename...R>              //
void print(const F f,const R...r){cout<<f<<", ";print(r...);}template<typename T>   //
void print(T*p, T*q){int d=p<q?1:-1;while(p!=q){cout<<*p<<", ";p+=d;}cout<<endl;}   //
                                                                                    //
typedef pair<intint> pii;                                                         //
typedef long long ll;                                                               //
typedef unsigned long long ull;                                                     //
                                                                                    //
template<typename T>bool umax(T&a, const T&b){return b<=a?false:(a=b,true);}        //
template<typename T>bool umin(T&a, const T&b){return b>=a?false:(a=b,true);}        //
template<typename T>                                                                //
void V2A(T a[],const vector<T>&b){for(int i=0;i<b.size();i++)a[i]=b[i];}            //
template<typename T>                                                                //
void A2V(vector<T>&a,const T b[]){for(int i=0;i<a.size();i++)a[i]=b[i];}            //
                                                                                    //
const double PI = acos(-1);                                                         //
                                                                                    //
/* -------------------------------------------------------------------------------- */
 
struct KM {
    const static int INF = 1e9 + 7;
    const static int maxn = 1e3 + 7;
    int A[maxn], B[maxn];
    int visA[maxn], visB[maxn];
    int match[maxn], slack[maxn], Map[maxn][maxn];
    int M, H;
 
    void add(int u, int v, int w) {
        Map[u][v] = w;
    }
    bool find_path ( int i ) {
        visA[i] = true;
        for int j = 0; j < H; j++ ) {
            if ( !visB[j] && A[i] + B[j] == Map[i][j] ) {
                visB[j] = true;
                if (match[j] == -1 || find_path(match[j])) {
                    match[j] = i;
                    return true;
                }
            else if ( A[i] + B[j] > Map[i][j] ) //j属于B,且不在交错路径中
                slack[j] = min(slack[j], A[i] + B[j] - Map[i][j]);
        }
        return false;
    }
 
    int solve (int M, int H) {
        this->M = M; this->H = H;
        int i, j, d;
        memset(A, 0, sizeof(A));
        memset(B, 0, sizeof(B));
        memset(match, -1, sizeof(match));
        for ( i = 0; i < M; i++ )
            for ( j = 0; j < H; j++ )
                A[i] = max (Map[i][j], A[i]);
        for ( i = 0; i < M; i++ ) {
            for ( j = 0; j < H; j++ )
                slack[j] = INF;
            while ( 1 ) {
                memset(visA, 0, sizeof(visA));
                memset(visB, 0, sizeof(visB));
                if ( find_path ( i ) ) break//从i点出发找到交错路径则跳出循环
                for ( d = INF, j = 0; j < H; j++ ) //取最小的slack[j]
                    if (!visB[j] && d > slack[j]) d = slack[j];
                for ( j = 0; j < M; j++ ) //集合A中位于交错路径上的-d
                    if ( visA[j] ) A[j] -= d;
                for ( j = 0; j < H; j++ ) //集合B中位于交错路径上的+d
                    if ( visB[j] ) B[j] += d;
                    else slack[j] -= d; //注意修改不在交错路径上的slack[j]
            }
        }
        int res = 0;
        for ( j = 0; j < H; j++ )
            if (~match[j]) res += Map[match[j]][j];
        return res;
    }
};//点从0开始编号
KM solver;
vector<pii> H, M;
 
int dist(pii a, pii b) {
    return abs(a.X - b.X) + abs(a.Y - b.Y);
}
 
int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt""r", stdin);
#endif // ONLINE_JUDGE
    int n, m;
    while (cin >> n >> m, n || m) {
        H.clear();
        M.clear();
        for (int i = 0; i < n; i ++) {
            char s[123];
            scanf("%s", s);
            for (int j = 0; s[j]; j ++) {
                if (s[j] == 'H') H.pb(mp(i, j));
                if (s[j] == 'm') M.pb(mp(i, j));
            }
        }
        for (int i = 0; i < H.size(); i ++) {
            for(int j = 0; j < M.size(); j ++) {
                solver.add(i, j, -dist(H[i], M[j]));
            }
        }
        cout << -solver.solve(H.size(), M.size()) << endl;
    }
    return 0;
}
/* ******************************************************************************** */

(2)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/* ******************************************************************************** */
#include <iostream>                                                                 //
#include <cstdio>                                                                   //
#include <cmath>                                                                    //
#include <cstdlib>                                                                  //
#include <cstring>                                                                  //
#include <vector>                                                                   //
#include <ctime>                                                                    //
#include <deque>                                                                    //
#include <queue>                                                                    //
#include <algorithm>                                                                //
#include <map>                                                                      //
#include <cmath>                                                                    //
using namespace std;                                                                //
                                                                                    //
#define pb push_back                                                                //
#define mp make_pair                                                                //
#define X first                                                                     //
#define Y second                                                                    //
#define all(a) (a).begin(), (a).end()                                               //
#define fillchar(a, x) memset(a, x, sizeof(a))                                      //
                                                                                    //
void RI(vector<int>&a,int n){a.resize(n);for(int i=0;i<n;i++)scanf("%d",&a[i]);}    //
void RI(){}void RI(int&X){scanf("%d",&X);}template<typename...R>                    //
void RI(int&f,R&...r){RI(f);RI(r...);}void RI(int*p,int*q){int d=p<q?1:-1;          //
while(p!=q){scanf("%d",p);p+=d;}}void print(){cout<<endl;}template<typename T>      //
void print(const T t){cout<<t<<endl;}template<typename F,typename...R>              //
void print(const F f,const R...r){cout<<f<<", ";print(r...);}template<typename T>   //
void print(T*p, T*q){int d=p<q?1:-1;while(p!=q){cout<<*p<<", ";p+=d;}cout<<endl;}   //
                                                                                    //
typedef pair<intint> pii;                                                         //
typedef long long ll;                                                               //
typedef unsigned long long ull;                                                     //
                                                                                    //
template<typename T>bool umax(T&a, const T&b){return b<=a?false:(a=b,true);}        //
template<typename T>bool umin(T&a, const T&b){return b>=a?false:(a=b,true);}        //
template<typename T>                                                                //
void V2A(T a[],const vector<T>&b){for(int i=0;i<b.size();i++)a[i]=b[i];}            //
template<typename T>                                                                //
void A2V(vector<T>&a,const T b[]){for(int i=0;i<a.size();i++)a[i]=b[i];}            //
                                                                                    //
const double PI = acos(-1);                                                         //
                                                                                    //
/* -------------------------------------------------------------------------------- */
 
struct MCMF {
    const static int INF = 1e9 + 7;
    const static int maxn = 1e5 + 7;
    struct Edge {
        int from, to, cap, cost;
        Edge(int u, int v, int w, int c): from(u), to(v), cap(w), cost(c) {}
    };
    int n, s, t;
    vector<Edge> edges;
    vector<int> G[maxn];
    int inq[maxn], d[maxn], p[maxn], a[maxn];
 
    void init(int n) {
        this->n = n;
        for (int i = 0; i < n; i ++) G[i].clear();
        edges.clear();
    }
    void add(int from, int to, int cap, int cost) {
        edges.push_back(Edge(from, to, cap, cost));
        edges.push_back(Edge(to, from, 0, -cost));
        int m = edges.size();
        G[from].push_back(m - 2);
        G[to].push_back(m - 1);
    }
    bool BellmanFord(int s, int t, int &flow, int &cost) {
        for (int i = 0; i < n; i ++) d[i] = INF;
        memset(inq, 0, sizeof(inq));
        d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF;
 
        queue<int> Q;
        Q.push(s);
        while (!Q.empty()) {
            int u = Q.front(); Q.pop();
            inq[u] = 0;
            for (int i = 0; i < G[u].size(); i ++) {
                Edge &e = edges[G[u][i]];
                if (e.cap && d[e.to] > d[u] + e.cost) {
                    d[e.to] = d[u] + e.cost;
                    p[e.to] = G[u][i];
                    a[e.to] = min(a[u], e.cap);
                    if (!inq[e.to]) {
                        Q.push(e.to);
                        inq[e.to] = 1;
                    }
                }
            }
        }
        if (d[t] == INF) return false;
        flow += a[t];
        cost += d[t] * a[t];
        int u = t;
        while (u != s) {
            edges[p[u]].cap -= a[t];
            edges[p[u] ^ 1].cap += a[t];
            u = edges[p[u]].from;
        }
        return true;
    }
    int solve(int s, int t) {
        int flow = 0, cost = 0;
        while (BellmanFord(s, t, flow, cost));
        return cost;
    }
};
MCMF solver;
vector<pii> H, M;
 
int dist(pii a, pii b) {
    return abs(a.X - b.X) + abs(a.Y - b.Y);
}
 
int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt""r", stdin);
#endif // ONLINE_JUDGE
    int n, m;
    while (cin >> n >> m, n || m) {
        solver.init(207);
        H.clear();
        M.clear();
        for (int i = 0; i < n; i ++) {
            char s[123];
            scanf("%s", s);
            for (int j = 0; s[j]; j ++) {
                if (s[j] == 'H') H.pb(mp(i, j));
                if (s[j] == 'm') M.pb(mp(i, j));
            }
        }
        for (int i = 0; i < H.size(); i ++) solver.add(0, i + 1, 1, 0);
        for (int i = 0; i < M.size(); i ++) solver.add(101 + i, 201, 1, 0);
        for (int i = 0; i < H.size(); i ++) {
            for(int j = 0; j < M.size(); j ++) {
                solver.add(i + 1, 101 + j, 1, dist(H[i], M[j]));
            }
        }
        cout << solver.solve(0, 201) << endl;
    }
    return 0;
}
/* ******************************************************************************** */

[hdu1533]二分图最大权匹配 || 最小费用最大流的更多相关文章

  1. “亚信科技杯”南邮第七届大学生程序设计竞赛之网络预赛 A noj 2073 FFF [ 二分图最大权匹配 || 最大费用最大流 ]

    传送门 FFF 时间限制(普通/Java) : 1000 MS/ 3000 MS          运行内存限制 : 65536 KByte总提交 : 145            测试通过 : 13 ...

  2. 经典网络流题目模板(P3376 + P2756 + P3381 : 最大流 + 二分图匹配 + 最小费用最大流)

    题目来源 P3376 [模板]网络最大流 P2756 飞行员配对方案问题 P3381 [模板]最小费用最大流 最大流 最大流问题是网络流的经典类型之一,用处广泛,个人认为网络流问题最具特点的操作就是建 ...

  3. poj 2195 二分图带权匹配+最小费用最大流

    题意:有一个矩阵,某些格有人,某些格有房子,每个人可以上下左右移动,问给每个人进一个房子,所有人需要走的距离之和最小是多少. 貌似以前见过很多这样类似的题,都不会,现在知道是用KM算法做了 KM算法目 ...

  4. Optimal Milking POJ - 2112 (多重最优匹配+最小费用最大流+最大值最小化 + Floyd)

      Optimal Milking Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 19347   Accepted: 690 ...

  5. POJ2195 Going Home[费用流|二分图最大权匹配]

    Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 22088   Accepted: 11155 Desc ...

  6. POJ2195 Going Home —— 最大权匹配 or 最小费用最大流

    题目链接:https://vjudge.net/problem/POJ-2195 Going Home Time Limit: 1000MS   Memory Limit: 65536K Total ...

  7. [kuangbin带你飞]专题十 匹配问题 二分图最大权匹配

    二分图最大权匹配有km算法和网络流算法 km算法模板默认解决最大权匹配的问题 而使用最小费用最大流 是解决最小权匹配问题 这两种办法都可以求最大最小权 需要两次取反 TAT 感觉讲km会很难的样子.. ...

  8. POJ2195 Going Home (最小费最大流||二分图最大权匹配) 2017-02-12 12:14 131人阅读 评论(0) 收藏

    Going Home Description On a grid map there are n little men and n houses. In each unit time, every l ...

  9. @noi.ac - 507@ 二分图最大权匹配

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 有一天你学了一个能解决二分图最大权匹配的算法,你决定将这个算法应 ...

随机推荐

  1. skynet启动流程及调用服务

     3.基本原理 3.1启动流程  1.skynet-src/skynet_main.c 这个是main()函数所在,主要就是设置一下lua的环境.默认的配置.打开config配置文件,并修改默认配置. ...

  2. 什么是LVM

    LVM是逻辑盘卷管理(Logical Volume Manager)的简称,它是Linux环境下对磁盘分区进行管理的一种机制,LVM是建立在硬盘和分区之上的一个逻辑层,来提高磁盘分区管理的灵活性.前面 ...

  3. DES加密解密算法C++实现

    DES加密算法并不难,是由一些简单的变换得来的,难的是要有足够的耐心.蒟蒻并不想说自己用了多久才把代码写好的. 代码: 我真的太难了QAQ #include<iostream> using ...

  4. Apache Rewrite实现URL的跳转和域名跳转

    Apache Rewrite实现URL的跳转和域名跳转   Rewirte主要的功能就是实现URL的跳转,它的正则表达式是基于Perl语言.可基 于服务器级的(httpd.conf)和目录级的 (.h ...

  5. chcp437 转换英语,在西班牙语系统中无效

    https://social.technet.microsoft.com/Forums/en-US/9c772011-5094-4df0-bf73-7140bf91673b/chcp-command- ...

  6. SVN diff

    http://svnbook.red-bean.com/en/1.6/svn.ref.svn.c.diff.html Name svn diff (di) — This displays the di ...

  7. SpringBoot中使用Fastjson/Jackson对JSON序列化格式化输出的若干问题

    来源 :https://my.oschina.net/Adven/blog/3036567 使用springboot-web编写rest接口,接口需要返回json数据,目前国内比较常用的fastjso ...

  8. Uva 1754 Posterize

    #include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=a;i<=b;++i) #defi ...

  9. UVALive 7509 Dome and Steles

    三分 #include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=a;i<=b;++i) #d ...

  10. Vue Router路由守卫妙用:异步获取数据成功后再进行路由跳转并传递数据,失败则不进行跳转

    问题引入 试想这样一个业务场景: 在用户输入数据,点击提交按钮后,这时发起了ajax请求,如果请求成功, 则跳转到详情页面并展示详情数据,失败则不跳转到详情页面,只是在当前页面给出错误消息. 难点所在 ...