zoukankan      html  css  js  c++  java
  • [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<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;
    }
    /* ******************************************************************************** */
  • 相关阅读:
    路径专题
    java.lang.IllegalArgumentException: Result Maps collection does not contain value for java.lang.Integer
    DER input, Integer tag error的异常处理
    myeclipse,eclipse控制台输出乱码问题
    大话设计模式之简单工厂模式
    Maven安装与配置
    IDEA: 遇到问题Error during artifact deployment. See server log for details.详解
    IntelliJ IDEA 中 右键新建时,选项没有Java class的解决方法和具体解释
    微信内置浏览器和小程序的 User Agent 区别及判断方法
    WAMP 403 Forbidden禁止访问
  • 原文地址:https://www.cnblogs.com/jklongint/p/4694982.html
Copyright © 2011-2022 走看看