[hdu1533]二分图最大权匹配 || 最小费用最大流
题意:给一个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< int , int > 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< int , int > 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]二分图最大权匹配 || 最小费用最大流的更多相关文章
- “亚信科技杯”南邮第七届大学生程序设计竞赛之网络预赛 A noj 2073 FFF [ 二分图最大权匹配 || 最大费用最大流 ]
传送门 FFF 时间限制(普通/Java) : 1000 MS/ 3000 MS 运行内存限制 : 65536 KByte总提交 : 145 测试通过 : 13 ...
- 经典网络流题目模板(P3376 + P2756 + P3381 : 最大流 + 二分图匹配 + 最小费用最大流)
题目来源 P3376 [模板]网络最大流 P2756 飞行员配对方案问题 P3381 [模板]最小费用最大流 最大流 最大流问题是网络流的经典类型之一,用处广泛,个人认为网络流问题最具特点的操作就是建 ...
- poj 2195 二分图带权匹配+最小费用最大流
题意:有一个矩阵,某些格有人,某些格有房子,每个人可以上下左右移动,问给每个人进一个房子,所有人需要走的距离之和最小是多少. 貌似以前见过很多这样类似的题,都不会,现在知道是用KM算法做了 KM算法目 ...
- Optimal Milking POJ - 2112 (多重最优匹配+最小费用最大流+最大值最小化 + Floyd)
Optimal Milking Time Limit: 2000MS Memory Limit: 30000K Total Submissions: 19347 Accepted: 690 ...
- POJ2195 Going Home[费用流|二分图最大权匹配]
Going Home Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 22088 Accepted: 11155 Desc ...
- POJ2195 Going Home —— 最大权匹配 or 最小费用最大流
题目链接:https://vjudge.net/problem/POJ-2195 Going Home Time Limit: 1000MS Memory Limit: 65536K Total ...
- [kuangbin带你飞]专题十 匹配问题 二分图最大权匹配
二分图最大权匹配有km算法和网络流算法 km算法模板默认解决最大权匹配的问题 而使用最小费用最大流 是解决最小权匹配问题 这两种办法都可以求最大最小权 需要两次取反 TAT 感觉讲km会很难的样子.. ...
- 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 ...
- @noi.ac - 507@ 二分图最大权匹配
目录 @description@ @solution@ @accepted code@ @details@ @description@ 有一天你学了一个能解决二分图最大权匹配的算法,你决定将这个算法应 ...
随机推荐
- js拼接onclick方法字符串参数解决方法
onclick = contentmap("'+useridarr[i]+'")
- atom跨平台超好用的markdown实时预览
https://atom.io/ sublime有预览markdown的插件,但仅限于每次在浏览器中预览,想要找一个能够实时在软件中预览的,终于发现了atom. 很多功能以插件的形式安装,theme也 ...
- python 基础篇 错误和异常处理
语法错误 所谓语法错误,也就是你写的代码不符合编程规范,无法被识别与执行,比如下面这个例子: if name is not None print(name) If 语句漏掉了冒号,不符合 Python ...
- 关于go的入门书籍——go自学的序
说实话,许世伟的<GO语言编程>,承载的心血是轻易可见的.但是我更喜欢那种工具书,就是简单说明他干嘛她干嘛,就能干嘛干嘛··· 比如读张晏关于<取代Apache的高性能Web服务器& ...
- 15分钟从零开始搭建支持10w+用户的生产环境(三)
上一篇文章介绍了这个架构中,选择MongoDB做为数据库的原因,及相关的安装操作. 原文地址:15分钟从零开始搭建支持10w+用户的生产环境(二) 三.WebServer 在SOA和gRPC大行其 ...
- Android-网页解析-gson的使用
相对于较为传统的Json解析来说,google共享的开源Gson在解析速度和所使用的内存在有着明显的优势,虽然说阿里巴巴也提供了fastgson包,但是它跟Gson的处理速度大同小异,只是底层实现的原 ...
- 解决从dockerhub上下载debian:jessie失败
解决从dockerhub上下载debian:jessie失败 笔者使用docker build 构建镜像出现下面的错误 Step 1/12 : FROM debian:jessie Get https ...
- CSS开发技巧(一):button样式设置
button样式需要注意的有几点: 1.建议有一个最小宽度,以免在文字很少时使得按钮过于窄,宽高不协调: 2.建议有一个padding,以免内部文本显得过于拥挤: 2.hover时需要有颜色变化,以告 ...
- Extmail邮件过滤和杀毒
前面整合好了extmail,不过没有测试使用foxmail这种客户端去测试收发邮件功能,今天测试的时候发现了蛮多问题,大部分和/etc/authmysqlrc这个文件的配置和权限相关,都是小问题,折腾 ...
- C++编程入门题目--No.5
题目: 输入三个整数x,y,z,请把这三个数由小到大输出. 程序分析: 我们想办法把最小的数放到x上,先将x与y进行比较,如果x>y则将x与y的值进行交换, 然后再用x与z进行比较,如果x> ...