| 13 | | |
| 14 | | class BlackKnot { |
| 15 | | vector<MarbleResult> m_results; |
| | 42 | ostream& operator<<(ostream& os, const MarbleResult& r) { |
| | 43 | return (os << "{ dest: " << r.dest << ", plinks: " << r.plinks << " }"); |
| | 44 | } |
| | 45 | |
| | 46 | |
| | 47 | struct Switcher { |
| | 48 | unsigned line; |
| | 49 | unsigned pos; |
| | 50 | |
| | 51 | Switcher(unsigned p_line = 0, unsigned p_pos = 0) |
| | 52 | : line(p_line), pos(p_pos) { } |
| | 53 | }; |
| | 54 | ostream& operator<<(ostream& os, const Switcher& sw) { |
| | 55 | return (os << "{ line: " << sw.line << ", pos: " << sw.pos << " }"); |
| | 56 | } |
| | 57 | |
| | 58 | |
| | 59 | struct BlackKnot { |
| | 60 | vector<MarbleResult> results; |
| | 61 | |
| | 62 | typedef vector<Switcher> Solution; |
| | 63 | |
| | 64 | BlackKnot(const char *specfile); |
| | 65 | |
| | 66 | Solution solve() const; |
| | 67 | void output_solution(const Solution& soln, ostream& os = cout) const; |
| | 68 | |
| | 69 | unsigned size() const { return results.size(); } |
| | 70 | }; |
| | 71 | ostream& operator<<(ostream& os, const BlackKnot& black); |
| | 72 | |
| | 73 | |
| | 74 | class Solver { |
| | 75 | const BlackKnot& black; |
| | 76 | |
| | 77 | BlackKnot::Solution switchers; |
| | 78 | vector<unsigned> marbles; // What marble in each position? |
| | 79 | vector<unsigned> plinks_left; |
| | 80 | unsigned line, pos; |
| | 81 | |
| | 82 | bool findSwitcher(); |
| | 83 | bool addSwitcher(); |
| | 84 | void removeSwitcher(); |
| | 85 | |
| | 86 | void doSwitch(const Switcher& sw, bool forward); |
| | 87 | bool checkDone() const; |
| 32 | | FILE *file = specfile ? fopen(specfile, "r") : stdin; |
| 33 | | unsigned source, dest, plinks; |
| 34 | | |
| 35 | | while (fscanf(file, " %u -> ( %u , %u ) \n", &source, &dest, &plinks) |
| 36 | | == 3) { |
| 37 | | if (source >= m_results.size()) { |
| 38 | | m_results.resize(source + 1); |
| 39 | | } |
| 40 | | m_results[source] = MarbleResult(dest, plinks); |
| 41 | | } |
| 42 | | |
| 43 | | fclose(file); |
| 44 | | } |
| 45 | | |
| 46 | | void BlackKnot::dump() const { |
| 47 | | for (size_t i = 0; i < m_results.size(); ++i) { |
| 48 | | printf("%zu -> (%u,%u)\n", i, m_results[i].dest, m_results[i].plinks); |
| 49 | | } |
| 50 | | } |
| | 111 | ifstream infile; |
| | 112 | istream* is; |
| | 113 | if (specfile) { |
| | 114 | infile.open(specfile); |
| | 115 | is = &infile; |
| | 116 | } else { |
| | 117 | is = &cin; |
| | 118 | } |
| | 119 | |
| | 120 | string s; |
| | 121 | while (getline(*is, s)) { |
| | 122 | // No good C++ replacement for scanf |
| | 123 | unsigned source, dest, plinks; |
| | 124 | if (sscanf(s.c_str(), " %u -> ( %u , %u ) \n", |
| | 125 | &source, &dest, &plinks) != 3) { |
| | 126 | cerr << "Error reading: '" << s << "'" << endl; |
| | 127 | break; |
| | 128 | } |
| | 129 | |
| | 130 | if (source >= results.size()) { |
| | 131 | results.resize(source + 1); |
| | 132 | } |
| | 133 | results[source] = MarbleResult(dest, plinks); |
| | 134 | } |
| | 135 | |
| | 136 | if (infile.is_open()) { |
| | 137 | infile.close(); |
| | 138 | } |
| | 139 | } |
| | 140 | |
| | 141 | void BlackKnot::output_solution(const BlackKnot::Solution& soln, |
| | 142 | ostream& os) const { |
| | 143 | BlackKnot::Solution::const_iterator iter = soln.begin(); |
| | 144 | unsigned line = 0; |
| | 145 | |
| | 146 | while (iter != soln.end()) { |
| | 147 | unsigned pos = 0; |
| | 148 | while (pos < size()) { |
| | 149 | if (iter != soln.end() |
| | 150 | && iter->line == line && iter->pos == pos) { |
| | 151 | os << "><"; |
| | 152 | pos += 2; |
| | 153 | ++iter; |
| | 154 | } else { |
| | 155 | os << "|"; |
| | 156 | ++pos; |
| | 157 | } |
| | 158 | } |
| | 159 | os << "\n"; |
| | 160 | ++line; |
| | 161 | } |
| | 162 | } |
| | 163 | |
| | 164 | ostream& operator<<(ostream& os, const BlackKnot& black) { |
| | 165 | for (unsigned i = 0; i < black.size(); ++i) { |
| | 166 | const MarbleResult& r = black.results[i]; |
| | 167 | os << i << " -> (" << r.dest << "," << r.plinks << ")\n"; |
| | 168 | } |
| | 169 | return os; |
| | 170 | } |
| | 171 | |
| | 172 | BlackKnot::Solution BlackKnot::solve() const { |
| | 173 | return Solver(*this).solve(); |
| | 174 | } |
| | 175 | |
| | 176 | Solver::Solver(const BlackKnot& p_black) |
| | 177 | : black(p_black), marbles(p_black.size()), line(0), pos(0) |
| | 178 | { |
| | 179 | iota(marbles.begin(), marbles.end(), 0); |
| | 180 | |
| | 181 | plinks_left.reserve(black.size()); |
| | 182 | vector<MarbleResult>::const_iterator iter; |
| | 183 | for (iter = black.results.begin(); iter != black.results.end(); ++iter) { |
| | 184 | plinks_left.push_back(iter->plinks); |
| | 185 | } |
| | 186 | } |
| | 187 | |
| | 188 | BlackKnot::Solution Solver::solve() { |
| | 189 | findSwitcher(); |
| | 190 | return switchers; |
| | 191 | } |
| | 192 | |
| | 193 | |
| | 194 | bool Solver::findSwitcher() { |
| | 195 | // Don't allow a completely empty line |
| | 196 | unsigned last_line = line + 1; |
| | 197 | |
| | 198 | while (line <= last_line) { |
| | 199 | if (pos < black.size() - 1) { |
| | 200 | if (addSwitcher()) { |
| | 201 | if (findSwitcher()) { |
| | 202 | return true; |
| | 203 | } else { |
| | 204 | removeSwitcher(); |
| | 205 | } |
| | 206 | } |
| | 207 | ++pos; |
| | 208 | } else { |
| | 209 | pos = 0; |
| | 210 | ++line; |
| | 211 | if (checkDone()) { |
| | 212 | return true; |
| | 213 | } |
| | 214 | } |
| | 215 | } |
| | 216 | return false; |
| | 217 | } |
| | 218 | |
| | 219 | void Solver::doSwitch(const Switcher& sw, bool forward) { |
| | 220 | unsigned orig_right = marbles[forward ? pos + 1 : pos]; |
| | 221 | int plink_delta = forward ? -1 : +1; |
| | 222 | plinks_left[orig_right] += plink_delta; |
| | 223 | |
| | 224 | swap(marbles[pos], marbles[pos+1]); |
| | 225 | } |
| | 226 | |
| | 227 | |
| | 228 | bool Solver::addSwitcher() { |
| | 229 | Switcher sw(line, pos); |
| | 230 | |
| | 231 | unsigned right = marbles[pos + 1]; |
| | 232 | if (plinks_left[right] == 0) { |
| | 233 | return false; |
| | 234 | } |
| | 235 | doSwitch(sw, true); |
| | 236 | |
| | 237 | switchers.push_back(sw); |
| | 238 | pos += 2; // Line gets fixed in findSwitcher |
| | 239 | return true; |
| | 240 | } |
| | 241 | |
| | 242 | void Solver::removeSwitcher() { |
| | 243 | Switcher sw(switchers.back()); |
| | 244 | switchers.pop_back(); |
| | 245 | |
| | 246 | doSwitch(sw, false); |
| | 247 | |
| | 248 | line = sw.line; |
| | 249 | pos = sw.pos; |
| | 250 | } |
| | 251 | |
| | 252 | bool Solver::checkDone() const { |
| | 253 | for (unsigned i = 0; i < black.size(); ++i) { |
| | 254 | const MarbleResult& result = black.results[i]; |
| | 255 | if (plinks_left[i] != 0 || marbles[result.dest] != i) { |
| | 256 | return false; |
| | 257 | } |
| | 258 | } |
| | 259 | return true; |
| | 260 | } |
| | 261 | |
| | 262 | ostream& operator<<(ostream& os, const Solver& s) { |
| | 263 | // TODO |
| | 264 | return os; |
| | 265 | } |
| | 266 | |
| | 267 | |
| | 268 | // Normal types |
| | 269 | template <typename T, bool U> struct Dumper { |
| | 270 | static void dump(const T& n, ostream& os, unsigned) { os << n; } |
| | 271 | static void dump_short(const T& n, ostream& os) { os << n; } |
| | 272 | }; |
| | 273 | |
| | 274 | // Containers |
| | 275 | template <typename T> struct Dumper<T, true> { |
| | 276 | typedef typename T::value_type U; |
| | 277 | |
| | 278 | static void dump(const T& n, ostream& os, unsigned indent) { |
| | 279 | string s1(indent, ' '), s2(indent + 1, ' '); |
| | 280 | os << "{\n"; |
| | 281 | |
| | 282 | typename T::const_iterator iter = n.begin(); |
| | 283 | unsigned idx = 0; |
| | 284 | for ( ; iter != n.end(); ++idx, ++iter) { |
| | 285 | os << s2 << setw(3) << idx << ". "; |
| | 286 | Dumper<U, has_const_iterator<U>::value>::dump(*iter, os, |
| | 287 | indent + 2); |
| | 288 | os << ",\n"; |
| | 289 | } |
| | 290 | os << s1 << "}"; |
| | 291 | } |
| | 292 | |
| | 293 | static void dump_short(const T& n, ostream& os) { |
| | 294 | os << "{ "; |
| | 295 | typename T::const_iterator iter = n.begin(); |
| | 296 | if (iter != n.end()) |
| | 297 | os << *iter++; |
| | 298 | while (iter != n.end()) |
| | 299 | os << ", " << *iter++; |
| | 300 | os << " }" << endl; |
| | 301 | } |
| | 302 | }; |
| | 303 | |
| | 304 | |
| | 305 | template <typename T> void dump(const T& n, ostream &os) { |
| | 306 | Dumper<T, has_const_iterator<T>::value>::dump(n, os, 0); |
| | 307 | os << endl; |
| | 308 | } |
| | 309 | |
| | 310 | template <typename T> void dump_short(const T& n, ostream& os) { |
| | 311 | Dumper<T, has_const_iterator<T>::value>::dump_short(n, os); |
| | 312 | os << endl; |
| | 313 | } |