Sortieren Sie eine Liste unbekannter Werte mit der geringsten Anzahl von Vergleichen

8

In dieser Optimierungsaufforderung schreiben Sie ein Programm, das ein einzelnes Array sortiert, indem Sie nur Elemente vergleichen, indem Sie den Benutzer auf stdout auffordern, Vergleichsergebnisse auf stdin einzugeben.

Das folgende Protokoll ist zeilenbasiert. Jedes Mal, wenn Sie in stdout drucken oder aus stdin lesen, wird davon ausgegangen, dass eine neue Zeile folgt. In der folgenden Frage wird davon ausgegangen, dass der Benutzer (gelesen: das Bewertungsprogramm) ein Array hat, das in einem 0-basierten indizierten Array mit dem Namen sortiert werden soll array. Aus technischen Gründen empfehle ich, nach jedem Druck zu spülen, um kräftig zu werden.

  1. Als ersten Schritt muss Ihr Programm die Arraygröße nvon stdin lesen .
  2. Dann können Sie so oft Sie möchten a < bmit zwei ganzen Zahlen auf stdout drucken 0 <= a, b < n. Dann gibt der Benutzer 1in stdin if array[a] < array[b]und 0andernfalls ein.
  3. Sobald Ihr Programm überzeugt ist, dass es die Reihenfolge des Arrays korrekt abgeleitet hat, muss es a ...in stdout drucken , wobei ...eine durch Leerzeichen getrennte Liste von Ganzzahlen die Reihenfolge angibt. Wenn Ihr Programm ausgegeben wird a 3 0 1 4 2, bedeutet dies, dass Ihr Programm abgeleitet hat

    array[3] <= array[0] <= array[1] <= array[4] <= array[2]
    

    Beachten Sie, dass Ihr Programm den Inhalt von nie kannte arrayund dies niemals tun wird.

Sie können nur <nach stdin fragen , um das Array zu sortieren. Sie können andere Vergleichsoperationen durch diese Äquivalenzen erhalten:

a > b        b < a
a <= b       !(b < a)
a >= b       !(a < b)
a != b       (a < b) || (b < a)
a == b       !(a < b) && !(b < a)

Da Ihr Programm mit dem Scoring-Programm auf stdout interagiert, drucken Sie die Debug-Informationen an stderr.


Ihr Programm wird mit dem folgenden Python-Programm bewertet:

from __future__ import print_function
from subprocess import Popen, PIPE
import sys, random

def sort_test(size):
    array = [random.randrange(0, size) for _ in range(size)]
    pipe = Popen(sys.argv[1:], stdin=PIPE, stdout=PIPE, bufsize=0, universal_newlines=True)
    print(str(size), file=pipe.stdin); pipe.stdin.flush()
    num_comparisons = 0
    while True:
        args = pipe.stdout.readline().strip().split()
        if args and args[0] == "a":
            answer_array = [array[int(n)] for n in args[1:]]
            if list(sorted(array)) != answer_array:
                raise RuntimeError("incorrect sort for size {}, array was {}".format(size, array))
            return num_comparisons
        elif len(args) == 3 and args[1] == "<":
            a, b = int(args[0]), int(args[2])
            print(int(array[a] < array[b]), file=pipe.stdin); pipe.stdin.flush()
            num_comparisons += 1
        else:
            raise RuntimeError("unknown command")

random.seed(0)
total = 0
for i in range(101):
    num_comparisons = sort_test(i)
    print(i, num_comparisons)
    total += num_comparisons
print("total", total)

Sie bewerten Ihr Programm durch Eingabe python score.py yourprogram. Die Bewertung erfolgt, indem Ihr Programm ein zufälliges Array jeder Größe von 0 bis 100 sortiert und die Anzahl der von Ihrem Programm angeforderten Vergleiche zählt. Diese zufälligen Arrays können Duplikate haben. Ihr Algorithmus muss in der Lage sein, gleiche Elemente zu verarbeiten. Falls es Duplikate gibt, gibt es keine Anforderungen an die Reihenfolge der gleichen Elemente. Wenn [0, 0]es sich also um ein Array handelt, spielt es keine Rolle, ob Sie a 0 1oder ausgeben a 1 0.

Möglicherweise optimieren Sie nicht speziell für die bestimmten Arrays, die das Scoring-Programm generiert. Ich kann den RNG-Samen jederzeit ändern. Antworten, die integrierte Sortieralgorithmen verwenden, dürfen aus Gründen des Interesses veröffentlicht werden, sind jedoch nicht konkurrierend.

Programm mit der niedrigsten Punktzahl gewinnt.

orlp
quelle
1
Welche Python-Version verwenden Sie?
Undichte Nonne
Wie lange hat es gedauert, Ihren Scoring-Algorithmus auszuführen?
Undichte Nonne
Welche Annahmen können wir über die maximale Größe des Eingabearrays treffen?
helloworld922
@ helloworld922 Theoretisch keine - Ihre Antwort sollte für jede Größe funktionieren. Wenn dies jedoch in einer Sprache wie C Mühe spart, ist die Unterstützung von bis zu 100 Elementen erforderlich.
Orlp
Es ist wichtig, die vom Scoring-Programm verwendete Python-Version zu klären, da Python 2 und 3 unterschiedliche Zufallssequenzen generieren. Oder vielleicht wäre es besser, wenn die Zufälligkeit aus einer genau spezifizierten deterministischen Quelle wie Hashlib stamme.
Anders Kaseorg

Antworten:

3

Python, Punktzahl 23069

Dies verwendet den Ford-Johnson-Algorithmus zum Sortieren von Zusammenführungseinfügungen.

from __future__ import print_function
import sys

def less(x, y):
    print(x, '<', y)
    sys.stdout.flush()
    return bool(int(input()))

def insert(x, a, key=lambda z: z):
    if not a:
        return [x]
    m = len(a)//2
    if less(key(x), key(a[m])):
        return insert(x, a[:m], key) + a[m:]
    else:
        return a[:m + 1] + insert(x, a[m + 1:], key)

def sort(a, key=lambda z: z):
    if len(a) <= 1:
        return a
    m = len(a)//2
    key1 = lambda z: key(z[-1])
    b = sort([insert(x, [y], key) for x, y in zip(a[:m], a[m:2*m])], key=key1)
    if len(a) % 2:
        b += [[a[-1], None]]
    for k in range(m, len(a)):
        l, i, (x, y) = max((-i.bit_length(), i, t) for i, t in enumerate(b) if len(t) == 2)
        b[:i + 1] = insert([x], b[:i], key=key1) + [[y]]
    if len(a) % 2:
        b.pop()
    return [x for x, in b]

print('a', ' '.join(map(str, sort(range(int(input()))))))
Anders Kaseorg
quelle
1

Python 3, 28462 Punkte

Schnelle Sorte. Der Drehpunkt befindet sich ganz links.

Die Punktzahl wird erwartet, weil:

\ displaystyle \ sum_ {i \ mathop = 0} ^ {100} i \ log_2i = 29945.648687873225

from __future__ import print_function
import sys
size = int(input())

def less(a, b):
    print(a, "<", b); sys.stdout.flush()
    return bool(int(input()))

def quicksort(array):
    if len(array) < 2:
        return array
    pivot = array[0]
    left = []
    right = []
    for i in range(1,len(array)):
        if less(array[i],pivot):
            left.append(array[i])
        else:
            right.append(array[i])
    return quicksort(left)+[pivot]+quicksort(right)

array = list(range(size))
array = quicksort(array)

print("a", " ".join(str(i) for i in array)); sys.stdout.flush()

Bewertungen für jede getestete Größe:

size score
0 0
1 0
2 1
3 3
4 6
5 8
6 11
7 12
8 15
9 17
10 23
11 33
12 29
13 32
14 37
15 45
16 58
17 47
18 52
19 79
20 72
21 60
22 85
23 138
24 87
25 98
26 112
27 107
28 128
29 142
30 137
31 136
32 158
33 143
34 145
35 155
36 169
37 209
38 163
39 171
40 177
41 188
42 167
43 260
44 208
45 210
46 230
47 276
48 278
49 223
50 267
51 247
52 263
53 293
54 300
55 259
56 319
57 308
58 333
59 341
60 306
61 295
62 319
63 346
64 375
65 344
66 346
67 370
68 421
69 507
70 363
71 484
72 491
73 417
74 509
75 495
76 439
77 506
78 484
79 458
80 575
81 505
82 476
83 500
84 535
85 501
86 575
87 547
88 522
89 536
90 543
91 551
92 528
93 647
94 530
95 655
96 580
97 709
98 671
99 594
100 637
total 28462
Undichte Nonne
quelle
@orlp hier übersetzt die letzte Zeile zu "WindowsError: [Fehler 193]% 1 ist keine korrekte Win32-Anwendung."
Undichte Nonne
1

Python 2 (nicht konkurrierend), 23471 Punkte

from __future__ import print_function
import sys
size = int(input())

def cmp(a, b):
    print(a, "<", b); sys.stdout.flush()
    return [1,-1][bool(int(input()))]

array = list(range(size))
array = sorted(array,cmp=cmp)

print("a", " ".join(str(i) for i in array)); sys.stdout.flush()

Bewertungen für jede getestete Größe:

size score
0 0
1 0
2 1
3 4
4 5
5 7
6 9
7 14
8 17
9 20
10 21
11 26
12 30
13 35
14 37
15 41
16 45
17 51
18 52
19 57
20 63
21 63
22 72
23 79
24 79
25 80
26 91
27 93
28 96
29 105
30 110
31 116
32 124
33 123
34 131
35 130
36 142
37 144
38 156
39 154
40 163
41 168
42 177
43 178
44 183
45 183
46 192
47 194
48 212
49 207
50 216
51 221
52 227
53 239
54 238
55 243
56 255
57 257
58 260
59 270
60 281
61 284
62 292
63 293
64 303
65 308
66 312
67 321
68 328
69 328
70 342
71 348
72 352
73 358
74 367
75 371
76 381
77 375
78 387
79 400
80 398
81 413
82 415
83 427
84 420
85 435
86 438
87 448
88 454
89 462
90 462
91 479
92 482
93 495
94 494
95 502
96 506
97 520
98 521
99 524
100 539
total 23471
Undichte Nonne
quelle
Ich denke, Python implementiert bereits eine sehr gute Sortierfunktion, wobei die optimale Anzahl von Vergleichen hier betrachtet wird: en.wikipedia.org/wiki/… Sieht so aus, als wäre dies eine Referenz für eine sehr sehr gute Basislinie.
halb
1

Python, 333300 Punkte

from __future__ import print_function
import sys

size = int(input())

def less(a, b):
    print(a, "<", b); sys.stdout.flush()
    return bool(int(input()))

array = list(range(size))
for _ in range(size):
    for i in range(0, size-1):
        if less(array[i+1], array[i]):
            array[i], array[i+1] = array[i+1], array[i]

print("a", " ".join(str(i) for i in array)); sys.stdout.flush()

Dies ist ein Beispielprogramm, das die einfachste Form von Bubblesort implementiert und immer n*(n-1)Vergleiche pro Array durchführt.

Ich habe dieses Programm durch Speichern sort.pyund Tippen bewertet python score.py python sort.py.

orlp
quelle
Wenn es genau ist, ist es Python 3. Ich sehe, indem ich printwie eine Funktion aussehe.
user48538
1
@ zyabin101 Jetzt ist es beides :)
Orlp