Полагаю, Python достаточно близок к псевдокоду.
Допустим, у нас есть n
кандидатов, пронумерованных от 0
до n - 1
.
Сначала вы можете вычислить матрицу beats[i][j]
, равную True
, если кандидат i
превосходит кандидата j
и False
в противном случае.
Теперь вычислите транзитивное замыкание матрицы, используя алгоритм Флойда-Варшалла:
for k in range(n):
for i in range(n):
for j in range(n):
beats[i][j] = beats[i][j] or (beats[i][k] and beats[k][j])
После этого матрица имеет немного другое значение: beats[i][j]
означает, что существует «путь биения» i -> c1 -> c2 -> ... -> j
, такой, что i
бьет c1
, c1
бьет c2
и так далее до j
.
Компоненты Schwartz - это те, в которых во всех парах i
, j
есть пути биения, идущие в обе стороны, и нет другого кандидата, который победил бы ни один из них (см. Раздел Википедии о свойствах, в которых упоминается top цикл ).
В основном для каждого кандидата i
попробуйте построить вокруг него компонент, например:
schwartz_components = []
for i in range(n):
schwartz_component = {i}
is_schwartz = True
for j in range(n):
if beats[j][i]:
if beats[i][j]:
schwartz_component.add(j)
else:
is_schwartz = False
if is_schwartz:
schwartz_components.append(schwartz_component)
schwartz_set = set.union(*schwartz_components)
print(schwartz_set)
Для набора Смита все будет немного по-другому, вам нужно начать с cannot_beat[i][j] = not beats[i][j]
, использовать Floyd-Warshall для этого, а затем построить набор вокруг каждого i
, добавив всех кандидатов с путем к это через отношение cannot_beat
.
Я думаю, что это будет примерно так (после шага Флойда-Варшалла):
smith_candidates = []
for i in range(n):
smith_candidate = {i}
for j in range(n):
if cannot_beat[i][j]:
smith_candidate.add(j)
smith_candidates.append(smith_candidate)
# Take the smallest candidate
smith_set = min(smith_candidates, key=len)
Возможно, где-то есть ошибка, но это примерно так.