CSES - Vertailut

Sinulle annetaan olio, jonka sisällä on luvuista 1,2,\dots,n muodostuva lista. Tehtäväsi on päätellä listan sisältö. Et voi kuitenkaan kysyä oliolta suoraan, mikä luku on missäkin listan kohdassa.

Voit tehdä oliolle kyselyjä, joissa kysyt kahden listan luvun suuruusjärjestystä. Voit tehdä enintään n \lfloor \log_2 n \rfloor kyselyä, minkä jälkeen tiedossasi tulee olla listan sisältö. Tässä \lfloor \cdots \rfloor tarkoittaa pyöristystä alaspäin kokonaisluvuksi. Esimerkiksi kun n=6, voit tehdä enintään 6 \cdot \lfloor \log_2 6 \rfloor = 12 kyselyä.

Toteuta tiedostoon comparisons.py funktio find_list, jolle annetaan parametrina olio. Funktion tulee palauttaa listan sisältö. Olion metodi list_size antaa listan koon. Metodi smaller(a, b) palauttaa True tarkalleen silloin, kun kohdassa a oleva luku on pienempi kuin kohdassa b oleva luku.

Funktiota testataan erilaisissa tapauksissa, joissa n on välillä 1 \dots 20. Funktion tulee toimia tehokkaasti kaikissa näissä tapauksissa.

Tehtäväpohjassa on esimerkki luokan Comparator toteutuksesta. Voit testata koodiasi tämän luokan avulla, mutta palvelimella luokan sisäinen toteutus on erilainen. Saat käyttää tehtävän ratkaisussa vain tässä kuvattuja olion metodeja etkä saa yrittää selvittää olion sisältöä muulla tavalla.

import math

class Comparer:
    def __init__(self, numbers):
        self.numbers = numbers
        self.counter = 0
        n = len(self.numbers)
        self.bound = n * math.floor(math.log2(n))

    def list_size(self):
        return len(self.numbers)

    def smaller(self, a, b):
        self.counter += 1
        if self.counter > self.bound:
            raise RuntimeError("too many comparisons")
        return self.numbers[a] < self.numbers[b]

def find_list(comparer):
    # TODO

if __name__ == "__main__":
    comparer = Comparer([3, 1, 2, 4])
    numbers = find_list(comparer)
    print(numbers) # [3, 1, 2, 4]

    comparer = Comparer([1, 6, 2, 5, 3, 4])
    numbers = find_list(comparer)
    print(numbers) # [1, 6, 2, 5, 3, 4]