题意:给一个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. B - How many integers can you find 杭电1976

     Now you get a number N, and a M-integers set, you should find out how many integers which are small ...

  2. Python函数的返回值和作用域

    函数的返回值和作用域 1.返回值 def guess(x):    if x > 3:        return "> 3"    else:        retu ...

  3. github使用--配置sshkey

    配置sshkey 好处:每次提代码都不要输入用户名和密码. 1.生成key: 输入命令ssh-keygen -t rsa -C "邮箱地址" [邮箱地址:注册github时填写的邮 ...

  4. Stream—一个早产的婴儿

    当你会关注这篇文章时,那么意味着你对Stream或多或少有些了解,甚至你在许多业务中有所应用.正如你所知,业界对Stream.lambda褒贬不一,有人认为它是银弹,也有人认为其降低了代码的可读性.事 ...

  5. SMTP发邮件(直接可用)实例

    string file = "邮件测试.txt";//放在Debug下的一个txt文件. MailAddress from = new MailAddress("自己的邮 ...

  6. 关于“xxx”object is not callable的异常

    参考博文:https://blog.csdn.net/yitiaodashu/article/details/79016671 所谓callable对象是指一个后边可以加()的对象,比如函数, 所以这 ...

  7. HTTP 前世今生

    HTTP 协议在我们身边随处可见,只要上网就离不开它.不论是用浏览器还是 App,不论是看新闻.短视频还是听音乐.玩游戏,后面总会有 HTTP 在默默为你服务. Http 协议是怎么来的?最开始是什么 ...

  8. 米特运输——(dfs)

    米特是D星球上一种非常神秘的物质,蕴含着巨大的能量.在以米特为主要能源的D星上,这种米特能源的运输和储 存一直是一个大问题.D星上有N个城市,我们将其顺序编号为1到N,1号城市为首都.这N个城市由N- ...

  9. Jetson AGX Xavier更换apt-get源

    使用apt-get安装时,会很慢,更换了国内的源后,就可以解决这个问题了. 1. 备份sources.list文件 sudo cp /etc/apt/sources.list /etc/apt/sou ...

  10. SQLI-LABS学习笔记(二)

    逼话少说,如有错误,烦请指出,谢谢 这两天生病,效率很低 第5关 打开页面 发现跟前几题不同,没有直接返回数据.. 加个单引号 You have an error in your SQL syntax ...