TopCoder SRM 371 Div. 1 Medium - ChessMatchup
Solution:
Just learnt Kuhn-Munkres algorithm, and tried a related problem. The problem is a straight forward modification of maximum weight perfect matching. Here is an implementation:
#include <iostream> #include <cstdio> #include <vector> #include <algorithm> #include <cassert> #include <cstring> using namespace std; int INF = (int) 1e9; class ChessMatchup { public: int adj[102][102]; int M, N; int l[102], S[102], T[102], Nq[102]; int path[102], match[102]; int root; int par[102]; void computeNq(){ memset(Nq, 0, sizeof Nq); for(int i=0;i<N;++i){ if(!S[i])continue; for(int j=N;j<2*N;++j){ if(l[i] + l[j] == adj[i][j]){ Nq[j] = 1; if(match[j] != i) par[j] = i; } } } } bool TequalsNq(){ for(int i=N;i<2*N;++i){ if(T[i] != Nq[i]) return false; } return true; } void augment_path(int v, int state){ int u = path[v]; if(u == v) return; if(state){ match[u] = v; match[v] = u; } augment_path(u, state^1); } int maximumScore(vector<int> us, vector<int> them){ N = us.size(); for(int i=0;i<N;++i) memset(adj[i], 0, sizeof adj[i]); memset(l, 0, sizeof l); for(int i=0;i<N;++i){ for(int j=0;j<N;++j){ int tmp = us[i] - them[j]; if(tmp > 0) tmp = 2; else if(tmp == 0) tmp = 1; else tmp = 0; adj[i][j+N] = tmp; adj[j+N][i] = tmp; } } for(int i=0;i<N;++i){ for(int j=0;j<N;++j){ l[i] = max(l[i], adj[i][j+N]); } } M = 0; for(int i=0;i<2*N;++i) match[i] = i; while(M != N){ memset(S, 0, sizeof S); memset(T, 0, sizeof T); for(int i=0;i<2*N;++i) path[i] = i; for(int i=0;i<N;++i){ if(match[i] == i){ S[i] = 1; root = i; break; } } while(true){ computeNq(); if(TequalsNq()){ int alpha = 12345; for(int i=0;i<N;++i){ if(!S[i])continue; for(int j=N;j<2*N;++j){ if(T[j])continue; alpha = min(alpha, l[i] + l[j] - adj[i][j]); } } assert(alpha != INF && alpha != 0); for(int i=0;i<2*N;++i){ if(S[i]) l[i] -= alpha; if(T[i]) l[i] += alpha; } computeNq(); } int y = -1; for(int i=N;i<2*N;++i){ if(Nq[i] && !T[i]) { y = i; break; } } assert(y >= 0); if(match[y] == y){ path[y] = par[y]; augment_path(y, 1); ++M; break; } else { path[y] = par[y]; path[match[y]] = y; S[match[y]] = 1; T[y] = 1; } } } int ans = 0; for(int i=0;i<2*N;++i){ ans += l[i]; } return ans; } };
Below is a short description of Hungarian method for finding maximum weight matching that I summarised last night :P
/* KUHN-MUNKRES ALGORITHM for MAXIMUM WEIGHT MATCHING. Given a bipartite graph, find the maximum weigth matching, i.e. the total sum of the weights of the matching is maximum. Representation of the bipartite graph: Let G = (V,E) be the graph, then there exist X \subset V and Y \subset V, such that 1. X \union Y = G 2. X \intersect Y = \empty 3. E \in (X \cross_product Y) For x \in X and y \in Y, (x,y) \in E, let w(x,y) be the weight of that edge. Terminologies: 1. _Perfect matching_ is a matching M \in E such that each vertex \in V is incident to one and only one edge \in M. 2. _Labelling_ l : V -> R is a function that labels vertices to real numbers. 3. A _feasible labelling_ is a labelling such that if x \in X and y \in Y, then l(x) + l(y) >= w(x,y) 4. The _equality graph_ of G has all the edges Eq in E with property l(x) + l(y) == w(x,y) for all (x,y) \in Eq 5. Let N(u) be the neighbors v of u, such that w(us,v) == l(u) + l(v). Furthermore, if S is a set of vertices, then N(S) = \union_{u \in S} N(u) 6. _Alternating path_ is a path that passes through edges \in M and E-M alternatingly. Alternating path is said to be _augmenting_ if two end points of the path are free vertices. 7. Augmenting path always has one more edge in E-M than M. Hence flipping them will result in bigger matching M'. 8. An alternating tree is a tree with a free vertex as the root, and all path from the root form alternating paths. Kurn-Munkres Theorem: For a feasible labelling l, if M is a perfect matching in Eq, then M is a maximum weight matching in G. Proof: Suppose M is a perfect matching in G, may not be in Eq. Then we have: \sum_{e \in M} w(e) <= \sum_{e = (x,y) \in M} l(x) + l(y) == \sum_{v \in V} l(v) So sum of l(v) is the upper bound to the weight of the matching. Therefore, if we have Mq be the perfect matching in Eq, then we have \sum_{e \in Mq} w(e) == \sum_{v \in V} l(v) which is optimal maximum weigth matching. #shown Hungarian Method: 1. Initialize a labelling l, and a matching M in Eq. 2. Let S be a set of vertices in X, and T be a set of vertices in Y. Initially S and T are both empty. 3. While M is not perfect matching: Choose a free vertex f \in X such that S contains f, and T is empty. i.e. S = {f}, T = {} 4. If N(S) == T: Improve labelling l to l' (therefore Eq to Eq'), by: Find alpha = \min_{x \in S, y \not \in T} l(x) + l(y) - w(x,y) then for all v \in V: if v \in S: l(v) = l(v) - alpha if v \in T: l(v) = l(v) + alpha otherwise, do nothing to l(v) This updates ascertain that: - if u \in S and v \in T, then if (u,v) \in Eq then (u,v) \in Eq' - if u \not \in S and v \not \in T, then if (u,v) \in Eq then (u,v) \in Eq' - for u \in S and v \not \in T, there will be some (u,v) \in Eq' Also ensuring the correctness of alternating tree built later on. 5. If N(S) != T: Consider a vertex y \in N(S) - T. If y is a free vertex, then we have an augmenting path from f to y: Augment M and go to 3. Otherwise, y is matched to a vertex x: Extend T = T \union y and S = S \union x, and go to 4. Running time complexity: O(V^3) */
No comments:
Post a Comment