Разложение перестановок на циклы с менее чем O(n) дополнительной памятью

#c #algorithm #matrix #permutation

Вопрос:

В настоящее время я пытаюсь найти алгоритм, который может найти циклическое разложение перестановки, заданной по этой формуле:

 s(i) = (i / w)   (i % w) * h;
 

где h и w -номера строк и столбцов матрицы (я хочу использовать ее для транспонирования матрицы на месте). Однако единственный известный мне алгоритм декомпозиции использует дополнительную память O(h * w), как это:

 std::vector<size_t> cycles;
std::vector<bool> visited(h * w, false);
for (size_t i = 0; i < h * w;   i) {
  if (!visited[i]) {
    visited[i] = true;
    cycles.push_back(i);
    // I don't need complete cycles, one member from each cycle is enough.
    for (size_t j = (i / w)   (i % w) * h; j != i;
         j = (j / w)   (j % w) * h) {
      visited[j] = true;
    }
  }
}
 

Поэтому мой вопрос в том, существует ли алгоритм, который может привести к одному и тому же cycles вектору, но для этого не потребуется такой вектор, как visited ?

Комментарии:

1. Интересно ли решение O(nCycles)-пространство, O(n^2)-время?

2. (Алгоритм в двух словах: для каждого i всегда проходите весь цикл , отслеживая элемент с наименьшим индексом k , видимый в цикле; добавляйте только i в cycles if i == k .)

3. @j_random_hacker это решение работает, но, к сожалению, оно набрало гораздо худшие результаты по тестам 🙁