题意:给一个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. Numpy学习-(1)

    记录我学习Numpy过程 1. 介绍 (1)NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库 ...

  2. CSRF(跨站请求伪造)学习总结

    前言 参考大佬的文章,附上地址 https://www.freebuf.com/articles/web/118352.html 什么是CSRF? CSRF,中文名字,跨站请求伪造,听起来是不是和XS ...

  3. PHP文件包含漏洞(利用phpinfo)复现

    0x01 简介 PHP文件包含漏洞中,如果找不到可以包含的文件,我们可以通过包含临时文件的方法来getshell.因为临时文件名是随机的,如果目标网站上存在phpinfo,则可以通过phpinfo来获 ...

  4. 关于Google下插件SwitchyOmega用法

    开启代理后,尽管访问很自由了,但是我的搬瓦工,是有流量限制的.所以,在之前,我开启一会自由访问模式(戏称),然后关一会,用来方便打开国内网站. 是的,我这么坚持了半个月,之后,就崩溃了,太尼玛繁琐了! ...

  5. udp协议与tcp协议

    TCP协议与UDP协议支持的应用协议 TCP支持的应用协议主要有:Telnet.FTP.SMTP等: UDP支持的应用层协议主要有:NFS(网络文件系统).SNMP(简单网络管理协议).DNS(主域名 ...

  6. [Inno Setup] 退出安装程序的两种方式

    1. 完全静默的退出 procedure ExitProcess(exitCode:integer); external 'ExitProcess@kernel32.dll stdcall'; ... ...

  7. 霍夫变换(Hough Transform)

    霍夫变换是图像处理中从图像中识别几何形状的基本方法之一,应用很广泛,也有很多改进算法.最基本的霍夫变换是从黑白图像中检测直线(线段). 我们先看这样一个问题: 设已知一黑白图像上画了一条直线,要求出这 ...

  8. 浅析 JS 中的作用域链

    作用域链的形成 在 JS 中每个函数都有自己的执行环境,而每个执行环境都有一个与之对应的变量对象.例如: var a = 2 function fn () { var a = 1 console.lo ...

  9. layui表格参数

    layui表格对数据进行用table样式展现 举个例子: <!doctype html> <html> <head> <meta charset=" ...

  10. 集训模拟赛-1-T1

    最近学校网课跟得紧没时间写知识点,就拿题解凑个数(bushi 而且前两天我打着打着题解电脑就突然死机 幸运的是 我没有保存(微笑) 废话不多说 上题目! 城市攻击 (city) (256MB,1s) ...