Problem:
Problem C: Stopped Watches

In the middle of Tyrrhenian Sea, there is a small volcanic island called Chronus. The island
is now uninhabited but it used to be a civilized island. Some historical records imply that the
island was annihilated by an eruption of a volcano about 800 years ago and that most of the
people in the island were killed by pyroclastic flows caused by the volcanic activity. In 2003, a
European team of archaeologists launched an excavation project in Chronus Island. Since then,
the project has provided many significant historic insights. In particular the discovery made
in the summer of 2008 astonished the world: the project team excavated several mechanical
watches worn by the victims of the disaster. This indicates that people in Chronus Island had
such a highly advanced manufacturing technology.

Shortly after the excavation of the watches, archaeologists in the team tried to identify what
time of the day the disaster happened, but it was not successful due to several difficulties. First,
the extraordinary heat of pyroclastic flows severely damaged the watches and took away the
letters and numbers printed on them. Second, every watch has a perfect round form and one
cannot tell where the top of the watch is. Lastly, though every watch has three hands, they
have a completely identical look and therefore one cannot tell which is the hour, the minute,
or the second (It is a mystery how the people in Chronus Island were distinguishing the three hands. Some archaeologists
guess that the hands might be painted with different colors, but this is only a hypothesis, as the paint was lost
by the heat.
). This means that we cannot decide the time indicated by a watch uniquely;
there can be a number of candidates. We have to consider different rotations of the watch.
Furthermore, since there are several possible interpretations of hands, we have also to consider
all the permutations of hands.

You are an information archaeologist invited to the project team and are asked to induce the
most plausible time interval within which the disaster happened, from the set of excavated
watches.

In what follows, we express a time modulo 12 hours. We write a time by the notation hh:mm:ss,
where hh, mm, and ss stand for the hour (hh = 00, 01, 02, . . . , 11), the minute (mm = 00,
01, 02, . . . , 59), and the second (ss = 00, 01, 02, . . . , 59), respectively. The time starts from
00:00:00 and counts up every second 00:00:00, 00:00:01, 00:00:02, . . ., but it reverts to 00:00:00
every 12 hours.

The watches in Chronus Island obey the following conventions of modern analog watches.

A watch has three hands, i.e. the hour hand, the minute hand, and the second hand,
though they look identical as mentioned above.

Every hand ticks 6 degrees clockwise in a discrete manner. That is, no hand stays between
ticks, and each hand returns to the same position every 60 ticks.

The second hand ticks every second.

The minute hand ticks every 60 seconds.

The hour hand ticks every 12 minutes.

At the time 00:00:00, all the three hands are located at the same position.

Because people in Chronus Island were reasonably keen to keep their watches correct and pyroclastic flows spread over the island quite rapidly, it can be assumed that all the watches were
stopped in a short interval of time. Therefore it is highly expected that the time the disaster
happened is in the shortest time interval within which all the excavated watches have at least
one candidate time.

You must calculate the shortest time interval and report it to the project team.

Input

The input consists of multiple datasets, each of which is formatted as follows.

n

s1 t1 u1

s2 t2 u2

.

.

.

sn tn un

The first line contains a single integer n (2 ≤ n ≤ 10), representing the number of the watches.
The three numbers si , ti , ui in each line are integers such that 0 ≤ si ,ti , ui ≤ 59 and they specify
the positions of the three hands by the number of ticks relative to an arbitrarily chosen position.

Note that the positions of the hands of a watch can be expressed in many different ways. For
example, if a watch was stopped at the time 11:55:03, the positions of hands can be expressed
differently by rotating the watch arbitrarily (e.g. 59 55 3, 0 56 4, 1 57 5, etc.) and as well by
permuting the hour, minute, and second hands arbitrarily (e.g. 55 59 3, 55 3 59, 3 55 59, etc.).

The end of the input is indicated by a line containing a single zero.

Output

For each dataset, output the shortest time interval within which all the watches given in the
dataset have at least one candidate time. The output must be written in a single line in the
following format for each dataset.

hh:mm:ss h'h':m'm':s's'

Each line contains a pair of times hh:mm:ss and, h'h':m'm':s's' indicating that the shortest
interval begins at hh:mm:ss and ends at h'h':m'm':s's' inclusive. The beginning time and the
ending time are separated by a single space and each of them should consist of hour, minute,
and second in two digits separated by colons. No extra characters should appear in the output.

In calculating the shortest interval, you can exploit the facts that every watch has at least one
candidate time and that the shortest time interval contains 00:00:00 only if the interval starts
from 00:00:00 (i.e. the shortest interval terminates before the time reverts to 00:00:00).

If there is more than one time interval that gives the shortest, output the one that first comes
after 00:00:00 inclusive.

Sample Input

3
8 8 18
32 32 32
57 2 57
5
49 3 49
7 30 44
27 21 21
33 56 56
21 46 4
3
45 52 28
36 26 36
20 55 50
10
33 8 39
50 57 43
35 21 12
21 17 11
16 21 58
45 40 53
45 30 53
39 1 8
55 48 30
7 48 15
0

Output for the Sample Input

00:00:00 00:00:10
06:14:56 06:32:09
07:27:37 07:32:02
05:17:40 05:21:03

Solution in Rust (judge verdict: Accepted)

use std::collections::HashSet;
use std::collections::BTreeMap;
use std::fmt::Display;
use std::ops::Neg;
use std::ops::Div;
use std::ops::Mul;
use std::ops::Add;
use std::ops::{AddAssign, Sub};
use std::cmp::max;
use std::collections::VecDeque;
use std::cmp::min;
use std::collections::BTreeSet;
use std::cmp::Ordering;
use std::fmt::Debug;

fn read_line() -> String {
    let mut buffer = String::new();
    std::io::stdin().read_line(&mut buffer).expect("No Line");
    buffer
}
fn read_lines<T: std::str::FromStr>(count: usize) -> Vec<T> {
    let mut buffer = String::new();
    let mut vec = Vec::with_capacity(count);
    for _ in 0 .. count {
        std::io::stdin().read_line(&mut buffer).expect("No Line");
        vec.push(buffer.trim().parse().ok().expect("Can't Parse"));
        buffer.clear();
    }
    vec
}
fn read_tabulate<R, T: Fn(&str)->R> (count: usize, transformer: T) -> Vec<R> {
    let mut buffer = String::new();
    let mut vec = Vec::with_capacity(count);
    for _ in 0 .. count {
        std::io::stdin().read_line(&mut buffer).expect("No Line");
        vec.push(transformer(buffer.trim()));
        buffer.clear();
    }
    vec
}
fn read_value<T: std::str::FromStr>() -> T {
    read_line().trim().parse().ok().unwrap()
}
fn read_values<T: std::str::FromStr>() -> Vec<T> {
    read_line().trim().split(' ').map(|x| x.parse().ok().expect("Can't Parse")).collect::<Vec<T>>()
}
macro_rules! freeze {
    ($($id:ident), *) => {
        $(let $id = $id;)*
    };
}
macro_rules! read_lines {
    ($ident: ident: [$block: block; $size: expr]) => {
        let $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
    (mut $ident: ident: [$block: block; $size: expr]) => {
        let mut $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
}
macro_rules! read {
    (mut $ident: ident: [$ty:ty]) => {
        let mut $ident = read_values::<$ty>();
    };
    ($ident: ident: [$ty:ty]) => {
        let $ident = read_values::<$ty>();
    };
    (mut $ident: ident: [[$ty:ty]; $size: expr]) => {
        let mut $ident = (0 .. $size).into_iter().map(|_| read_values::<$ty>()).collect::<Vec<_>>();
    };
    ($ident: ident: [[$ty:ty]; $size: expr]) => {
        let $ident = (0 .. $size).into_iter().map(|_| read_values::<$ty>()).collect::<Vec<_>>();
    };
    (mut $ident: ident: [$ty:ty; $size:expr]) => {
        let mut $ident = read_lines::<$ty>($size);
    };
    ($ident: ident: [$ty:ty; $size:expr]) => {
        let $ident = read_lines::<$ty>($size);
    };
    ($ident: ident: [$block: block; $size: expr]) => {
        let $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
    (mut $ident: ident: [$block: block; $size: expr]) => {
        let mut $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
    ($($token: tt)*) => {
        let mut iter = read_values::<String>().into_iter();
        read_from_iter!(iter; $($token)*);
    };
}
macro_rules! read_from_iter {
    ($iter:expr; mut $ident:ident:$ty:ty, $($rest:tt)*) => {
        let mut $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
        read_from_iter!($iter; $($rest)*);
    };
    ($iter:expr; $ident:ident:$ty:ty, $($rest:tt)*) => {
        let $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
        read_from_iter!($iter; $($rest)*);
    };
    ($iter:expr; mut $ident:ident:$ty:ty) => {
        let mut $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
    };
    ($iter:expr; $ident:ident:$ty:ty) => {
        let $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
    };
    ($iter: expr; ) => {};
}
struct KeyValue<K, V> {
    key: K,
    value: V
}
impl <K: PartialOrd, V> PartialEq for KeyValue<K, V> {
    fn eq(&self, other: &Self) -> bool {
        self.key.eq(&other.key)
    }
}
impl <K: PartialOrd, V> Eq for KeyValue<K, V> {}
impl <K: PartialOrd, V> PartialOrd for KeyValue<K, V> {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        self.key.partial_cmp(&other.key)
    }
}
impl <K: PartialOrd, V> Ord for KeyValue<K, V> {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.key.partial_cmp(&other.key).ok_or("Can't Compare").unwrap()
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
struct Time {
    hour: i32, minute: i32, second: i32
}
impl Time {
    fn to_int(&self) -> i32 {
        self.hour * 3600 + self.minute * 60 + self.second
    }
    fn to_clock(&self) -> Clock {
        Clock{needle_a: (self.to_int() / 720) % 60, needle_b: (self.to_int() / 60) % 60, needle_c: self.to_int() % 60 }
    }
    fn from_int(second: i32) -> Time {
        let second = (second % 86400 + 86400) % 86400;
        Time{hour: second / 3600, minute: (second % 3600) / 60, second: second % 60}
    }
}
impl Sub for Time {
    type Output = Time;
    fn sub(self, rhs: Time) -> <Self as std::ops::Sub<Time>>::Output { 
        Time::from_int((self.to_int() - rhs.to_int() + 86400) % 86400)
    }
}
impl PartialOrd for Time {
    fn partial_cmp(&self, rhs: &Time) -> std::option::Option<std::cmp::Ordering> { 
        self.to_int().partial_cmp(&rhs.to_int())
     }
}
impl Ord for Time {
    fn cmp(&self, rhs: &Self) -> std::cmp::Ordering { 
        self.to_int().cmp(&rhs.to_int())
    }
}
impl Display for Time {
    fn fmt<'a>(&self, fmt: &mut std::fmt::Formatter<'a>) -> std::result::Result<(), std::fmt::Error> { 
        write!(fmt, "{:02}:{:02}:{:02}", self.hour, self.minute, self.second)
    }
}
#[derive(Copy, Clone, Eq, PartialEq)]
struct Clock {
    needle_a: i32, needle_b: i32, needle_c: i32
}
impl Clock {
    fn all_suspect(&self) -> Vec<Time> {
        self.shuffled().into_iter().flat_map(|clock| (0 .. 60).flat_map(move |offset| clock.rotate(offset).try_time())).collect::<Vec<_>>()
    }
    fn shuffled(&self) -> Vec<Clock> {
        vec![
            *self,
            Clock{needle_a: self.needle_a, needle_b: self.needle_c, needle_c: self.needle_b},
            Clock{needle_a: self.needle_b, needle_b: self.needle_a, needle_c: self.needle_c},
            Clock{needle_a: self.needle_b, needle_b: self.needle_c, needle_c: self.needle_a}, 
            Clock{needle_a: self.needle_c, needle_b: self.needle_a, needle_c: self.needle_b},
            Clock{needle_a: self.needle_c, needle_b: self.needle_b, needle_c: self.needle_a}
        ]
    }
    fn rotate(&self, angle: i32) -> Clock {
        Clock{needle_a: (self.needle_a + angle % 60 + 60) % 60, needle_b: (self.needle_b + angle % 60 + 60) % 60, needle_c: (self.needle_c + angle % 60 + 60) % 60}
    }
    fn try_time(&self) -> Option<Time> {
        if self.needle_b / 12 != self.needle_a % 5 {
            None
        }else {
            Some(Time{hour: self.needle_a / 5, minute: self.needle_b, second: self.needle_c})
        }
    }
}
fn lower_bound<T: Ord>(vec: &Vec<T>, target: &T) -> usize {
    let mut min = 0;
    let mut max = vec.len();
    while min < max {
        let mid = (min + max) >> 1;
        if &vec[mid] < target {
            min = mid + 1;
        }else {
            max = mid;
        }
    }
    max
}
fn main() {
    loop {
        read!(n: usize);
        if n == 0 {break;}
        read_lines! {
            clocks: [{
                read!(s: i32, t: i32, u: i32);
                Clock{needle_a: s, needle_b: t, needle_c: u}
            }; n]
        }
        let times = clocks.iter().map(|c| {
            let mut s = c.all_suspect();
            s.sort();
            s
        }).collect::<Vec<_>>();
        let mut start_times = times.iter().flat_map(|f|f.clone()).collect::<Vec<_>>();
        start_times.sort();
        let mut min_start = Time{hour: 0, minute: 0, second: 0};
        let mut min_end = Time{hour: 11, minute: 59, second: 59};
        for start_time in start_times.into_iter().rev() {
            let end_time: Vec<Time> = times.iter().flat_map(|time| {
                let end = lower_bound(time, &start_time);
                if end == time.len() {
                    None
                }else {
                    Some(time[end])
                }
            }).collect::<Vec<_>>();
            if end_time.len() == times.len() {
                let &max_end = end_time.iter().max().unwrap();
                if (min_end - min_start) >= (max_end - start_time) {
                    min_start = start_time;
                    min_end = max_end;
                }
            }
        }
        println!("{} {}", min_start, min_end);
    }
}