POJ 2724 - Purifying Machine
http://poj.org/problem?id=2724
概要
2^N 個のチーズがあり,それぞれ二進数で 00...0, ..., 11...1 と番号が割り当てられている. そのうち,与えられた M 個のパターンにマッチするようなチーズがウイルスに感染している. 同様のパターンを用いて浄化するとき,すべてのチーズを浄化するのに必要な最小のパターン数を答える.
パターンとは 0, 1, * からなる長さ N の列で,1つのパターンには高々1つしか * は含まれない.
* の桁の数字は 0 にも 1 にもマッチする.
例えば N = 6 のとき,01*100
というパターンは,チーズ 010100
とチーズ 011100
にマッチする.
制約
- 1 <= N <= 10
- 1 <= M <= 1000
解法
* を使って1つのパターンで浄化できるペア,すなわちハミング距離が1のペアにエッジを張って二部グラフの最大マッチングを求めれば,それが * を使ってまとめられるペアの最大の数であるため,チーズの個数からこれを引いたものが答えになる.
poj/2724.cc1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 using namespace std; 5 6 bool bm_augment(const vector<vector<int> >& g, int u, vector<int>& match_to, vector<bool>& visited)/*{{{*/ 7 { 8 if (u < 0) { 9 return true; 10 } 11 12 for (vector<int>::const_iterator it(g[u].begin()); it != g[u].end(); ++it) { 13 if (!visited[*it]) { 14 visited[*it] = true; 15 if (bm_augment(g, match_to[*it], match_to, visited)) { 16 match_to[*it] = u; 17 return true; 18 } 19 } 20 } 21 return false; 22 }/*}}}*/ 23 24 void coloring(const vector<vector<int> >& g, int u, vector<int>& color)/*{{{*/ 25 { 26 for (vector<int>::const_iterator it = g[u].begin(); it != g[u].end(); ++it) { 27 if (color[*it] == 0) { 28 color[*it] = -color[u]; 29 coloring(g, *it, color); 30 } 31 } 32 }/*}}}*/ 33 34 int bipartite_matching(const vector<vector<int> >& g)/*{{{*/ 35 { 36 const int N = g.size(); 37 vector<int> color(N, 0); 38 for (int u = 0; u < N; u++) { 39 if (color[u] == 0) { 40 color[u] = 1; 41 coloring(g, u, color); 42 } 43 } 44 vector<int> match_to(N, -1); 45 int match = 0; 46 vector<bool> visited(N); 47 for (int u = 0; u < N; u++) { 48 if (color[u] == 1) { 49 fill(visited.begin(), visited.end(), false); 50 if (bm_augment(g, u, match_to, visited)) { 51 match++; 52 } 53 } 54 } 55 return match; 56 }/*}}}*/ 57 58 int main() 59 { 60 int N, M; 61 while (cin >> N >> M && N != 0) { 62 vector<int> v; 63 for (int i = 0; i < M; i++) { 64 string s; 65 cin >> s; 66 if (s.find('*') != string::npos) { 67 int n = 0, m = 0; 68 for (string::const_iterator it = s.begin(); it != s.end(); ++it) { 69 if (*it == '*') { 70 n = 2*n + 0; 71 m = 2*m + 1; 72 } else { 73 n = 2*n + (*it-'0'); 74 m = 2*m + (*it-'0'); 75 } 76 } 77 v.push_back(n); 78 v.push_back(m); 79 } else { 80 int n = 0; 81 for (string::const_iterator it = s.begin(); it != s.end(); ++it) { 82 n = 2*n + (*it-'0'); 83 } 84 v.push_back(n); 85 } 86 } 87 sort(v.begin(), v.end()); 88 v.erase(unique(v.begin(), v.end()), v.end()); 89 90 vector<vector<int> > g(1<<N); 91 for (vector<int>::const_iterator it = v.begin(); it != v.end(); ++it) { 92 for (vector<int>::const_iterator jt = it+1; jt != v.end(); ++jt) { 93 if (__builtin_popcount(*it ^ *jt) == 1) { 94 g[*it].push_back(*jt); 95 g[*jt].push_back(*it); 96 } 97 } 98 } 99 100 cout << v.size()-bipartite_matching(g) << endl; 101 } 102 return 0; 103 }