Editorial for IOI '14 P3 - Game
Submitting an official solution before solving the problem yourself is a bannable offence.
Let be the set of edges about which the contestant has answered "yes" (connected), the set of edges about which contestant has answered "no", and the rest of the edges, whose statuses are not yet determined. Also, let and . is the graph you get by assuming that all edges in are not connected, while is the graph you get by assuming that all edges in are connected.
Initially, is empty and thus not connected, while is connected. In order not to reveal any clue to the judge, the contestant should maintain the invariant: should always be disconnected, while should always be connected.
There are several possible ways to maintain the invariant.
An solution
When asked by the judge whether an edge is connected, answer "no" if and only if is part of a cycle in . One can see that this does not change the connectivity of and .
To decide whether forms a circle, one can perform a depth-first search to find out whether there is a path from to in . This is an operation. As there are edges, the total running time is .
In other words, we answer "yes" if and only if is a bridge in .
An solution
Given a vertex , let be the connected component belongs to in . We maintain two data structures:
- is a table mapping each to a representative of .
- is a symmetric matrix indexed by . For and in , if , is the number of edges, in , that connects and .
The contestant answers "yes" to query if and only if .
can be implemented as a disjoint-set linked list. Each disjoint set is represented by a linked list of its elements, and the representative is the one at the head. Each element has a pointer to its representative. To unite two sets, we connect the lists and update the pointers. A union takes time and a find takes time.
As for , initially unless . Whenever the judge asks about , is updated as follows.
- If the contestant answers "no", we decrement by .
- If the contestant answers "yes", let be the representative after uniting and . For each that is a representative of some connected component, both and are updated to .
There can be at most unions, thus the total time spent on union is . An update of requires time for a "no" response, and time for a "yes" response. Since the graph is a tree, we respond "yes" exactly times. Thus the time spent on updating is also . We thus have an algorithm.
A One-Liner Algorithm
There is a surprising one-line algorithm:
#include "game.h"
void initialize(int n) {
// DO NOTHING!
}
int c[1500];
int hasEdge(int u, int v) {
return ++c[u > v ? u : v] == (u > v ? u : v);
}
To understand the algorithm, imagine that we partition the set of all the possible edges into , with . Each has exactly possible edges. The algorithm above answers "yes" to (where ) if it is the last edge in that is queried.
To see how it works, consider the last query. Denote the queried edge by , and the graph . The contestant wins if is disconnected, while is connected.
- is disconnected, since it contains only edges.
- is connected, since it contains edges, and there is no cycle in . One can see that there is no cycle since, in each , we answer yes to only one edge. Formally, if there is a cycle in , considering the node in with largest id, must have exactly one edge in . But has two neighbors in with smaller ids, a contradiction.
Comments