[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@ 有一天你学了一个能解决二分图最大权匹配的算法,你决定将这个算法应 ...
随机推荐
- 今天我们来谈谈绝对定位和相对定位的区别,和需要注意的问题;position:absolute|relative;
首先position:absolute|relative; 前者是绝对定位,后者是相对定位: position属性的四个值: static,relative,fixed,absolute; 重点重点重 ...
- [php代码审计]bluecms v1.6 sp1
一.环境搭建 bluecms v1.6 sp1源码 windows 7 phpstudy2016(php 5.4.45) seay源代码审计系统 源码在网上很容易下载,很多教程说访问地址 http:/ ...
- [转载]深度理解Session
什么是session session的官方定义是:Session:在计算机中,尤其是在网络应用中,称为“会话控制”.Session 对象存储特定用户会话所需的属性及配置信息. 说白了session就是 ...
- 单图像三维重建、2D到3D风格迁移和3D DeepDream
作者:Longway Date:2020-04-25 来源:单图像三维重建.2D到3D风格迁移和3D DeepDream 项目网址:http://hiroharu-kato.com/projects_ ...
- 关于log4j、jul、jcl、slf4j等等日志组件的理解
日志组件: 我们经常在开发项目的时候,需要打印记录项目过程中的一些日志.那我们经常大概会用到 log4j.jul.jcl.slf4j.simple.nop.logback 等等,那我们就详细介绍下这些 ...
- js拼接php拼接
当我们用到ajax的时候,局部替换的时候,我们可以在前台拼接,后台拼接,这个取决于你是前端后端这样拼接判断比较好, 判断不拼接,判断的值进行拼接 然后在html 替换 $.each 前台循环 ...
- SQLI-LABS学习笔记(四)
第十六关 和之前的关卡一样,修改闭合,无意义的关卡 ")闭合即可 第十七关 这题从源码上看发现 这里进行了两次查询 先查询了用户名是否存在 再查询密码是否匹配 ...
- markdownPad常用功能示例
1.列表 无序列表 姓名 张三 李四 王五 有序列表 张三 李四 王五 2.超链接 百度 3.引用 锄禾日当午,汗滴禾下土.谁知盘中餐,粒粒皆辛苦. -- 李绅<古风二首> 4.简要修饰文 ...
- 通过config文件配置动态导入模块
需求: 固定的服务中要调用不同的算法,当前服务中实现的动态导入是通过在config配置中加上参数:proto="AiProto(1,4)",在服务中from pathname im ...
- Ansible 配置文件详解
# config file for ansible -- http://ansible.com/ # ============================================== # ...