Блог о математике, программировании, алгоритмах. И немного о работе операционной системы Linux.

четверг, 11 ноября 2010 г.

Генерация случайного дерева

В ходе работы над дипломом мне пришлось столкнуться с необходимостью генерации дерева. Так как я точно не знаю, какое именно дерево будет описывать мою задачу (деревом представляется булева функция общего вида), я решил, что будет логично прогнать алгоритмы на достаточно большом количестве случайных деревьев. Итак, генерация случайного дерева.

В качестве структуры данных, для хранения была выбрана матрица смежности. Будем считать, что дерево — ориентированный граф с полустепенью захода у каждой вершины равной 1 (кроме корня: у него 0). Также нам нужно сделать так, чтобы у нас был всего один корень (то есть нам нужно именно дерево, а не лес).
Матрица смежности — это булева матрица, в (i, j) вершине которого содержится информация о том, присутствует ли в графе ребро изходящее из i и входящее в j. Из этого легко получить условия, которые мы должны наложить на матрицу, чтобы она описывала именно дерево.
  1. В столбце i (i > 0) должна стоять одна и только одна единица на месте j (j < i). Таким образом мы обеспечим полустепень захода равную 1 для всех вершин графа, кроме корня. Будем, для удобства считать, что корнем является нулевая вершина.
  2. Ниже главной диагонали (и на ней) должны стоять нули, это обеспечит ориентированность дерева, и тот факт, что вершины с большим номером будут являтся детьми, только вершинам с меньшим номером.
Ниже я привожу небольшу программку для примера, генерирующую случайное дерево и выводящую результат в dot-cовместимом формате.
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>

int
main(int argc, char** argv)
{
    using namespace std;
    srand(time(NULL));
    vector<vector<int> > matrix;
    #define size 1000
    matrix.resize(size);
    for (int i = 0; i < size; i++) {
        matrix[i].resize(size);
        for (int j = 0; j < size; j++) {
            matrix[i][j] = 0;
        }
    }
    for (int i = size - 1; i > 0; i--) {
        /**
         * (rand() % i) - случайное число в множестве [0, i)
         * i-тый столбец
         */
        matrix[rand() % i][i] = 1;
    }
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++) {
            if (matrix[i][j] == 1) {
                cout << i << " -> " << j << ";" << endl;
            }
        }
    }
}
И на закуску небольшой пример:
0 1 0 0 0
0 0 1 1 0
0 0 0 0 1
0 0 0 0 0
0 0 0 0 0
Дерево, представленное этой матрицей будет выглядеть так:
Обратите внимание, что четвертая и пятая строки в матрице содержат только нули. На графе они стали листьями. Столбец содержащий одни нули (1-ый) является корнем.