Urutkan daftar nilai yang tidak diketahui dengan jumlah perbandingan paling sedikit

8

Dalam tantangan pengoptimalan ini, Anda akan menulis sebuah program yang mengurutkan satu array dengan hanya membandingkan elemen melalui meminta pengguna di stdout untuk memasukkan hasil perbandingan pada stdin.

Protokol di bawah ini berbasis garis, jadi setiap kali Anda mencetak ke stdout atau membaca dari stdin, diasumsikan bahwa baris baru akan mengikuti. Sepanjang pertanyaan di bawah ini diasumsikan bahwa pengguna (baca: program penilaian) memiliki sebuah array yang ingin disortir dalam array yang diindeks berbasis 0 yang disebut array. Untuk alasan teknis, saya sarankan pembilasan setelah setiap cetak menjadi gagah.

  1. Sebagai langkah pertama Anda, program Anda harus membaca ukuran array ndari stdin.
  2. Kemudian, sesering yang Anda inginkan, Anda dapat mencetak a < bke stdout, dengan dua bilangan bulat 0 <= a, b < n. Maka pengguna akan masuk 1dalam stdin jika array[a] < array[b], dan 0sebaliknya.
  3. Akhirnya, setelah program Anda yakin itu telah dengan benar menyimpulkan urutan array, itu harus mencetak a ...ke stdout, di mana ...adalah daftar spasi yang dipisahkan bilangan bulat yang menunjukkan urutan. Jadi jika program Anda menghasilkan a 3 0 1 4 2itu berarti program Anda telah menyimpulkan

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

    Perhatikan bahwa program Anda tidak pernah tahu isinya array, dan tidak akan pernah tahu.

Anda hanya bisa meminta <pada stdin untuk mengurutkan array. Anda bisa mendapatkan operasi perbandingan lainnya dengan persamaan ini:

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

Akhirnya, karena program Anda berinteraksi dengan program penilaian di stdout, cetak informasi debug ke stderr.


Program Anda akan dinilai menggunakan program Python berikut:

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)

Anda menilai program Anda dengan mengetik python score.py yourprogram. Penilaian dilakukan dengan meminta program Anda mengurutkan satu array acak dari setiap ukuran 0 hingga 100 dan menghitung jumlah perbandingan yang diminta oleh program Anda. Array acak ini dapat memiliki duplikat , algoritme Anda harus dapat menangani elemen yang sama. Jika ada duplikat, tidak ada persyaratan pada urutan elemen yang sama. Jadi jika arraynya [0, 0]tidak masalah apakah Anda output a 0 1atau a 1 0.

Anda tidak dapat mengoptimalkan secara spesifik untuk array tertentu yang dihasilkan oleh program penilaian. Saya dapat mengubah benih RNG kapan saja. Jawaban yang menggunakan algoritme penyortiran bawaan diizinkan untuk diposting demi kepentingan, tetapi tidak bersaing.

Program dengan kemenangan skor terendah.

orlp
sumber
1
Versi Python mana yang Anda gunakan?
Leaky Nun
Berapa lama untuk menjalankan algoritme pemberian skor Anda?
Leaky Nun
Asumsi apa yang dapat kita buat pada ukuran maksimum dari array input?
helloworld922
@ helloworld922 Secara teoritis, tidak ada - jawaban Anda harus bekerja untuk ukuran berapa pun. Tetapi jika itu menghemat upaya dalam bahasa seperti C yang mendukung semuanya hingga dan mencakup 100 elemen diperlukan.
orlp
Penting untuk memperjelas versi Python yang digunakan oleh program penilaian, karena Python 2 dan 3 menghasilkan urutan acak yang berbeda. Atau mungkin akan lebih baik jika keacakan berasal dari sumber deterministik yang ditentukan dengan baik seperti hashlib.
Anders Kaseorg

Jawaban:

3

Python, skor 23069

Ini menggunakan algoritma sorting penyisipan gabungan Ford-Johnson.

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
sumber
1

Python 3, skor 28462

Sortir cepat. Pivot adalah item paling kiri.

Skor diharapkan, karena:

\ 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()

Skor untuk setiap ukuran yang diuji:

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
Biarawati Bocor
sumber
@ Atau di sini , baris terakhir diterjemahkan menjadi "WindowsError: [Kesalahan 193]% 1 bukan aplikasi Win32 yang benar."
Leaky Nun
1

Python 2 (non-bersaing), skor 23471

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()

Skor untuk setiap ukuran yang diuji:

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
Biarawati Bocor
sumber
Saya pikir Python sudah mengimplementasikan fungsi penyortiran yang sangat bagus, melihat perbandingan jumlah yang optimal di sini: en.wikipedia.org/wiki/... Sepertinya ini akan menjadi referensi untuk baseline yang sangat sangat bagus.
justhalf
1

Python, skor 333300

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()

Ini adalah contoh program, mengimplementasikan bentuk paling sederhana dari bubbleort, selalu melakukan n*(n-1)perbandingan per larik.

Saya mencetak program ini dengan menyimpannya sebagai sort.pydan mengetik python score.py python sort.py.

orlp
sumber
Jika tepat, itu Python 3. Saya melihat dengan printmelihat seperti fungsi.
user48538
1
@ zyabin101 Sekarang keduanya :)
orlp