Solution to Problem 2: Rank Fraud
Let the ministers be M_1, M_2, ... M_N. The task of the prime
minister is to order them as M_i1, M_i2, ... M_iN such that for
each j, M_ij beat M_i{j+1} in the table-tennis tournament.
As mentioned earlier, the description of the problem as a set
(the set of Ministers) and a binary relationship (who beat who)
suggests the use of graphs in solving this problem. Let the
vertices of the graph be { 1, 2, 3, ..., N } representing the N
ministers with a directed edge from i to j if j beats i in the
table-tennis tournament.
For instance, if the results of the matches between 4 ministers
are as follows: Minister 1 beat ministers 2 and 4, Minister 2
beats none, Minister 3 beat ministers 1 and 2, and Minister 4
beat ministers 2 and 3. The graph representing these results
would look like:
--------------------------
| |
1 <------------- 2 -- |
^ | | |
| ---------- | |
| | | |
| | | |
4 <------------- 3 <------
Examining this graph we can conclude that 2 loses to 3, 3 loses
to 4 and 4 loses to 1 and thus 2, 3, 4, 1 would be a possible
order in which the prime minister could present the ministers to
the king.
Thus out aim is to find a path through the directed graph that
includes all the vertices (note that by definition any vertex can
appear at the most once in any path). Such a path is called a ``
Hamiltonian Path ''. There are no known algorithms that can
compute or even check if a given graph contains a Hamiltonian
path efficiently. It is believed that any algorithm to solve this
problem will take at least 2^N steps where N is the number of
vertices in the graph.
However, the graph that is obtained from the results of the
table-tennis tournament has a special feature --- for each pair
of vertices i and j there is exactly one edge involving the two
of them, either from i to j or from j to i. Such a directed graph
is called a ``Tournament'' (since the results of round-robin
tournaments, such as the above, produce such graphs). It turns
out that first of all, every tournament does have a Hamiltonian
path and secondly, such a path can be calculated quite
efficiently. Let us see how.
We construct paths of length i for each i < N. We may pick any
edge in the tournament to get a path of length 1. Pick any path
of length i-1, say v_1,v_2,v_3, ..., v_i. We show that it can be
extended to a path of length i. Pick any vertex v that does not
appear among v_1, v_2, ... v_i. Since i<N, such a vertex always
exists.
1) If the edge between v and v_1 (recall there must be one,
by the definition of a tournament) is from v to v_1 then our
desired path is v, v_1, ..., v_i.
2) Otherwise, if the edge between v and v_i is from v_i to v then
our desired path is v_1, v_2, ... v_i, v.
3) Otherwise the situation is as follows:
v_1 ----> v_2 ----> v_3 ... v_{i-1} ----> v_i
| ^
| |
-----------------------> v ----------------------
We scan right from v_1 to v_i to find the first vertex v_j
such that the edge between v and v_j is oriented from v to
v_j. Such a vertex must exist (since the edge between v and
v_i is oriented from v to v_i, there is at least one and
thus there must be a left most and this left most is not
v_1). For this j, we have edges v_{j-1} -----> v and v
-----> v_j. Then,
v_1 ----> v_2 ----> ... v_{j-1} ----> v ----> v_j ... ----> v_i
is a path of length i. Thus, starting with any edge, one
can successively construct paths of length 2,3, and so on
up to N-1. Thus, we can construct a Hamiltonian path.
How efficiently can this algorithm be implemented?
In each iteration, we need to find a vertex that is not already
in the path and insert it in the appropriate position. This can
be done in time proportional to N. There are N-2 insertions and
thus, this algorithm can be implemented in time proportional to
N*N. The details are as follows:
--------------------------------------------------------------------------
/* We assume that the graph is stored as an adjacency matrix
A. */
/* Initialise H with a path of length 1 */
If (A[1][2]=1) {
H[1]=1;
H[2]=2;
}
else {
H[1]=2;
H[2]=1;
}
Present[1]=1;
Present[2]=1;
for i = 2 to N-1 do {
for k = 3 to N do {
if (Present[j]=0) break;
}
/* k is vertex that has not been inserted yet. */
/* so insert it. *
if (G[k][H[1]] = 1) then
insert k at the beginning of H
else if (G[H[i]][k] = 1)
insert k at the end of H
else { /* case 3. find the position j to insert k */
for j=1 to N
if (G[k][j] = 1) break;
insert k between the (j-1)st and jth elements
currently in H
}
Present[k] = 1
}
Print out the array H.
-------------------------------------------------------------------------