#include #include #include #include #include #include #include #include #include /* Randomised solution based on the backtracking algorithm. Instead of backtracking, we just start over, randomising our choices. Will find the answer eventually, but should be rare. We use a fixed seed, so that the solution is deterministic. BUT we use a time bound, making it non-deterministic. */ using namespace std; // Since the checking is fast, we can probably get away with // setting the time_limit to the exact limit... const long double time_limit = 0.85; int main() { int n; cin >> n; // adjacency lists vector> graph(n); for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { char c; cin >> c; if (c == '1') graph[i].push_back(j); } } mt19937 gen; uniform_int_distribution coin(0, 1); // fair coin const auto time_bound = chrono::steady_clock::now() + chrono::duration(time_limit); long long tries = 0; while(chrono::steady_clock::now() < time_bound) { tries++; vector done(n, false); done[0] = true; // Henk will always have played in the end int count = 1; deque solution; int current = 0; // start with henk while(count < n) { // randomise the order of edges shuffle(graph[current].begin(), graph[current].end(), gen); bool progress = false; // Try the first person to extend the game for (auto j : graph[current]) { // skip the done ones if (done[j]) continue; done[j] = true; count++; if(coin(gen)) { // beat j, continuing with current as king solution.push_front(j); progress = true; } else { // or, we can continue with j as king solution.push_front(current); current = j; progress = true; } } // if we were not able to make progress // it means we have to try again if(!progress) { break; } } // everyone played -> solved! if (count == n) { // initial player solution.push_front(current); cout << solution[0]; for (int j = 1; j < n; ++j) { cout << ' ' << solution[j]; } cout << endl; clog << tries << endl; exit(0); } else { // try again! continue; } } cout << "impossible" << endl; clog << tries << endl; }