标签:
题意:给一个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++ ) 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; } /* ******************************************************************************** */ |
标签:
原文地址:http://www.cnblogs.com/jklongint/p/4694982.html