Classifique uma lista de valores desconhecidos com a menor quantidade de comparações

8

Neste desafio de otimização, você escreverá um programa que classifica uma única matriz comparando apenas os elementos, solicitando ao usuário no stdout que insira resultados de comparação no stdin.

O protocolo abaixo é baseado em linhas; portanto, toda vez que você imprime em stdout ou lê em stdin, assume-se uma nova linha. Ao longo da pergunta abaixo, supõe-se que o usuário (leia-se: o programa de pontuação) tenha uma matriz que deseja classificar em uma matriz indexada baseada em 0 chamada array. Por razões técnicas, sugiro a descarga após cada impressão para ser robusta.

  1. Como seu primeiro passo, seu programa deve ler o tamanho nda matriz em stdin.
  2. Então, quantas vezes quiser, você pode imprimir a < bem stdout, com dois números inteiros 0 <= a, b < n. Em seguida, o usuário entrará 1em stdin if array[a] < array[b]e de 0outra forma.
  3. Finalmente, uma vez que seu programa está convencido de que deduziu corretamente a ordem da matriz, ele deve imprimir a ...em stdout, onde ...há uma lista separada por espaços de números inteiros indicando a ordem. Portanto, se o seu programa produzir a 3 0 1 4 2, significa que ele deduziu

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

    Observe que seu programa nunca conheceu o conteúdo arraye nunca saberá.

Você só pode solicitar <no stdin para classificar a matriz. Você pode obter outras operações de comparação por estas equivalências:

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

Por fim, como seu programa interage com o programa de pontuação no stdout, imprima as informações de depuração no stderr.


Seu programa será pontuado usando o seguinte programa Python:

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)

Você pontua seu programa digitando python score.py yourprogram. A pontuação é feita com o programa ordenando uma matriz aleatória de cada tamanho de 0 a 100 e contando a quantidade de comparações solicitadas pelo programa. Essas matrizes aleatórias podem ter duplicatas , seu algoritmo deve ser capaz de lidar com elementos iguais. No caso de haver duplicatas, não há requisitos na ordem dos elementos iguais. Portanto, se a matriz estiver [0, 0], não importa se você produz a 0 1ou a 1 0.

Você não pode otimizar especificamente para as matrizes específicas que o programa de pontuação gera. Eu posso mudar a semente RNG a qualquer momento. É permitido que as respostas que utilizam algoritmos de classificação internos sejam publicadas por interesse, mas não sejam concorrentes.

Programa com menor pontuação ganha.

orlp
fonte
1
Qual versão do Python você está usando?
Leaky Nun
Quanto tempo levou para executar seu algoritmo de pontuação?
Leaky Nun
Que suposições podemos fazer sobre o tamanho máximo da matriz de entrada?
precisa
@ helloworld922 Teoricamente, nenhuma - sua resposta deve funcionar para qualquer tamanho. Porém, se economizar esforço em uma linguagem como C, é necessário suportar tudo, incluindo até 100 elementos.
orlp 21/07
É importante esclarecer a versão do Python usada pelo programa de pontuação, porque o Python 2 e 3 geram sequências aleatórias diferentes. Ou talvez seja melhor se a aleatoriedade vier de uma fonte determinística bem especificada, como o hashlib.
Anders Kaseorg 21/07

Respostas:

3

Python, pontuação 23069

Isso usa o algoritmo de classificação de inserção de mesclagem 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
fonte
1

Pontuação do Python 3, 28462

Ordenação rápida. O pivô é o item mais à esquerda.

A pontuação é esperada, porque:

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

Pontuações para cada tamanho testado:

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
Freira Furada
fonte
@ orlp aqui , a última linha se traduz em "WindowsError: [Erro 193]% 1 não é um aplicativo Win32 correto".
Leaky Nun
1

Python 2 (não concorrente), pontuação 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()

Pontuações para cada tamanho testado:

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
Freira Furada
fonte
Eu acho que o Python já implementa uma função de classificação muito boa, observando o número ideal de comparações aqui: en.wikipedia.org/wiki/… Parece que isso será uma referência para uma linha de base muito boa.
justhalf 21/07
1

Pontuação do Python, 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()

Este é um programa de exemplo, implementando a forma mais simples de bolhas, sempre fazendo n*(n-1)comparações por matriz.

Marquei este programa salvando-o como sort.pye digitando python score.py python sort.py.

orlp
fonte
Se for exato, é o Python 3. Vejo printparecendo uma função.
user48538
1
@ zyabin101 Agora são as duas coisas :)
orlp