题意:给一个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. adb命令查看手机应用内存使用情况

    adb shell回车 一.procrank VSS >= RSS >= PSS >= USSVSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)是单个 ...

  2. Cucumber(4)——jenkins的集成

    目录 回顾 必备知识 集成方法 回顾 在上几节中,关于cucumber的知识我已经全部的介绍完了,但是近期,jenkins大行其道,在工作上面能为我们节省大量的时间. 所以在本节中,我会介绍cucum ...

  3. 15分钟从零开始搭建支持10w+用户的生产环境(二)

    上一篇文章,把这个架构的起因,和操作系统的选择进行了详细说明. 原文地址:15分钟从零开始搭建支持10w+用户的生产环境(一)   二.数据库的选择 对于一个10W+用户的系统,数据库选择很重要. 一 ...

  4. 漫谈LiteOS-端云互通组件-MQTT开发指南(上)

    1.介绍 SDK简介 Agent Tiny是部署在具备广域网能力.对功耗/存储/计算资源有苛刻限制的终端设备上的轻量级互联互通中间件,您只需调用API接口,便可实现设备快速接入到物联网平台以及数据上报 ...

  5. java 一维数组的总结笔记

    数组 1. 一位数组的声明方式 type[] array Name 或 type arrayName[];(推荐使用第二种) 错误的声明方式 //int[5] intErrorArray;错误的 // ...

  6. 页面性能分析-Chrome Dev Tools

    一.分析面板介绍 进行页面性能快速分析的主要是图中圈出来的几个模块功能: Network : 页面中各种资源请求的情况,这里能看到资源的名称.状态.使用的协议(http1/http2/quic...) ...

  7. ES6的 Iterator 遍历器到底是什么?

    这节课要讲的是ES6中的Iterator. for...of为啥不遍历Object对象 第十三节我们讲了简单又实用的for...of,我们可以使用它来遍历数组,字符串,Set和Map结构,但是有没有发 ...

  8. ES6让字符串String增加了哪些好玩的特性呢?

    确实因为现在天气变热了,所以一天天的这么写我也很累.所以如果阅读的时候有什么错误还请大家指出来,不好意思.学习永无止境. OK,今天继续讲解ES6系列知识 学过上一节的解构赋值就知道,ES6确实给我们 ...

  9. 解决Oracle在命令行下无法使用del等键问题

    前言: Oracle使用Linux命令行进行编辑? 有PL/SQL development,SQL development等工具,为何用Linux命令行? 但也免不了有用的的时候 以下是解决在Linu ...

  10. GDI+ 绘制砂岩含量图版

    图版是在工作中经常会使用到的工具,它能够大大提高我们日常工作效率.地质图版在地质工作中具有举足轻重的作用,不仅可以轻松判断岩性,也可以依据经验图版直接得到结果,十分方便. 本程序目的绘制出一个地质常用 ...