假设你有25个对象,一台机器可以根据一些你甚至不知道的标准对其中的5个对象进行排序。使用这台机器的成本非常昂贵(一次发射需要1美元),那么对所有物品进行分类的最低成本是多少?
我目前的解决方案非常简单(类似于merge sort):
随机分成5组,每组5个对象
对每一个进行排序(+5次发布)
现在,对这五个组的最小元素进行排序(+1次启动)
现在我们得到了整个集合的最小元素。将其从所属的组中移除,然后重复步骤3,直到只剩下5个未排序的对象(启动时间为+19)
对其余5个对象进行排序(+1次启动)
所以,一般来说,我们必须支付26美元(26次发射)。
问:有什么方法可以使它更便宜(以最少的发射次数分类)?

最佳答案

下面是一个贪婪的算法,用于在每次迭代时选择要排序的对象:
排序25个对象ai与完全填充表m25x25相同,其中mi,如果ai>a j,j=1,否则-1。在您使用机器执行一次排序迭代后,您将获得刚刚排序的元素之间的直接关系(最多可立即填充5个单元格),但之后您可以使用交换性(即,如果a>b,则您知道bb和b>c,则您知道a>c)。
若要选择5个元素进行下一次排序,请选择元素,在与这些元素相对应的行和列的交叉点中有大多数空单元格。因此,你可以比较所有可能的组合。有25个选择5=53130个可能的变体,复杂性实际上是指数型的,但是在这个问题上不需要任何“钱”。
当表被完全填充时,您可以使用Topological sort构建排序序列,或者只需根据相应表行中的值之和对元素进行排序:总和越高,元素就越大。
这并不理想,但相当有效。我已经在随机排列上测试了这个方法,结果平均约为16.8美元。以下是python中的代码示例:

import random
import itertools


class SortingMachine:
    def __init__(self):
        self.coins = 0

    def sort(self, elements):
        assert(len(elements) == 5)
        self.coins += 1
        return list(sorted(elements))


def test_sorting(seq):
    N = len(seq)
    machine = SortingMachine()
    table = [[0 if i == j else None for j in range(N)] for i in range(N)]

    # Fill empty table cells using transitivity with Floyd-Warshall algorithm
    def fill_transitive():
        for k in range(N):
            for i in range(N):
                for j in range(N):
                    if table[i][j] is None and table[i][k] == table[k][j]:
                        table[i][j] = table[i][k]

    # Register in the table the information that seq[i] > seq[j]
    def set_greater(i, j):
        table[i][j] = 1
        table[j][i] = -1

    # Register in the table information from 5 sorted elements
    def register_sorted(sub):
        for (el1, i1), (el2, i2) in zip(sub, sub[1:]):
            set_greater(i2, i1)

    # Select 5 elements to send to the machine
    def choose_elements():
        # Count empty cells in the cells corresponding to 5 comb elements
        def empty_cells(comb):
            return sum(table[i][j] is None
                       for i, el1 in comb for j, el2 in comb)
        comb = max((empty_cells(comb), comb)
                   for comb in itertools.combinations(enumerate(seq), 5))[1]
        return [(el, ind) for ind, el in comb]

    # Return True if the table is completely filled
    def is_complete():
        return all(all(el is not None for el in row) for row in table)

    while not is_complete():
        chosen = choose_elements()
        sorted_chosen = machine.sort(chosen)
        register_sorted(sorted_chosen)
        fill_transitive()

    # Checking that the sorting is correct
    sorted_seq = list(sorted(seq))
    assert(all(sorted_seq.index(seq[ind]) == (sum(row) + N - 1) // 2
               for ind, row in enumerate(table)))

    return machine.coins


def random_sequence():
    l = list(range(25))
    random.shuffle(l)
    return l

贪心启发式在这种方法中,最大限度地只获得从排序获得的即时信息,而不考虑传递性。现在,理论上,一个更好的启发式是最大化预期信息,对所选择的5个元素进行排序,包括通过传递性获得的所有信息。也就是说,选择5个元素,具有最大平均值(超过所有可能的排序结果)后的填充细胞数考虑及物性。但实现这种算法需要更长的计算时间。

关于algorithm - 给定一台可以分类5个对象的机器。我们可以对其中的25种进行分类的速度有多快?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30265140/

10-11 20:01