├── .gitignore ├── Makefile ├── README.md ├── contents.rb ├── cpp ├── first_half │ ├── BFS.cc │ ├── BI.cc │ ├── CC.cc │ ├── DEGREE.cc │ ├── DFS.cc │ ├── DenseGRAPH.cc │ ├── DenseMultiGRAPH.cc │ ├── EC.cc │ ├── EULER.cc │ ├── Edge.cc │ ├── EdgeOptimalSparseGRAPH.cc │ ├── EdgeSorter.cc │ ├── EdgeSorter.h │ ├── GQ.cc │ ├── GRAPH.cc │ ├── IO.cc │ ├── InfoDFS.cc │ ├── MapST.cc │ ├── PFS.cc │ ├── SCc.cc │ ├── SCg.cc │ ├── SCt.cc │ ├── SEARCH.cc │ ├── ST.cc │ ├── STLSparseMultiGRAPH.cc │ ├── SparseGRAPH.cc │ ├── SparseMultiGRAPH.cc │ ├── StaticGRAPH.cc │ ├── StaticMultiGRAPH.cc │ ├── TC.cc │ ├── TCsc.cc │ ├── UndirBitDenseGRAPH.cc │ ├── UndirDenseGRAPH.cc │ ├── cDFS.cc │ ├── clients.cc │ ├── dagTC.cc │ ├── dagTSq.cc │ ├── dagTSr.cc │ ├── dagTSs.cc │ ├── ePATH.cc │ ├── gPATH.cc │ ├── inputs.txt │ ├── main.cpp │ ├── main_17-6.cpp │ ├── process_mem_usage.cc │ ├── process_mem_usage.h │ ├── sPATH.cc │ └── tc.cc └── second_half │ ├── DenseGRAPH.cc │ ├── EDGE.cc │ ├── GRAPH.cc │ ├── IO.cc │ ├── MSTbr.cc │ ├── MSTcr.cc │ ├── MSTpr.cc │ ├── PQi.cc │ ├── SparseMultiGRAPH.cc │ ├── UF.cc │ ├── WeightedEdge.cc │ ├── a.out │ ├── clients.cc │ ├── inputs.txt │ ├── main.cc │ └── sort.cc └── ruby ├── basic.rb ├── generator.rb ├── hash.rb └── mm.rb /.gitignore: -------------------------------------------------------------------------------- 1 | obj 2 | ps 3 | graph 4 | temp 5 | 0..1000.txt 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GCC_PATH := /usr 2 | CXX := $(GCC_PATH)/bin/g++ 3 | CXXFLAGS := -Wall -O2 -I$(GCC_PATH)/include -L$(GCC_PATH)/lib 4 | 5 | NAME := graph 6 | SRC_DIR := cpp 7 | OBJ_DIR := obj 8 | SOURCE_FILES := $(wildcard $(SRC_DIR)/*.cc) 9 | OBJECT_FILES := $(addprefix $(OBJ_DIR)/,$(notdir $(SOURCE_FILES:.cc=.o))) 10 | 11 | $(NAME): $(OBJECT_FILES) 12 | $(CXX) $(CXXFLAGS) -o $@ $^ $(SRC_DIR)/main.cpp 13 | 14 | $(OBJ_DIR): 15 | mkdir -p $(OBJ_DIR) 16 | 17 | $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cc | $(OBJ_DIR) 18 | $(CXX) $(CXXFLAGS) -c -o $@ $< 19 | 20 | clean: 21 | rm -f $(NAME) 22 | 23 | cleanall: clean 24 | rm -rf $(OBJ_DIR) 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Роберт Седжвик 2 | 3 | ## Фундаментальные алгоритмы на C++ [часть 5] 4 | 5 | # Алгоритмы на графах 6 | 7 | В настоящем репозитарии содержатся программы и алгоритмы из вышеуказанной книги, а также некоторые выполненные упражнения. Оформление кода не претендует на идеал или образец (скорее наоборот), и по большей части навеян содержимым книги. Где это было возможно - он оставался без изменений. 8 | 9 | Особенно, кстати, следует отметить книгу издательства DiaSoft от 2002 года, что на 496 страницах, ибо это жосткий перевод, с грубыми опечатками, что немного усложняет освоение изложенного в книге материала. 10 | 11 | ### Программы из текста 12 | 13 | * [Программа 4.11. Реализация АДТ "Отношения эквивалентности"](https://github.com/newmen/graph-algorithms/blob/master/cpp/second_half/UF.cc) 14 | * [Программа 6.1. Пример сортировки массива с помощью управляющей программы](https://github.com/newmen/graph-algorithms/blob/master/cpp/second_half/sort.cc) 15 | * [Программа 17.1 (расширеная). Интерфейс АДТ графа](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/GRAPH.cc) 16 | * [Программа 17.1. Интерфейс ребра графа](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/Edge.cc) 17 | * [Программа 17.2. Пример клиентской функции обработки графов](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/clients.cc) 18 | * [Программа 17.3. Клиентская функция печати графа](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/IO.cc) 19 | * [Программа 17.4 (расширенная). Интерфейс ввода/вывода для функций обработки графов](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/IO.cc) 20 | * [Программа 17.5, 18.4. Интерфейс связности, Связность графа](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/CC.cc) 21 | * [Программа 17.6. Пример клиентской программы обработки графов](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/main_17-6.cpp) 22 | * [Программа 17.7 (расширенная). Реализация АДТ графа (матрица смежности)](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/DenseGRAPH.cc) 23 | * [Программа 17.8. Итератор для представления матрицы смежности](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/DenseGRAPH.cc) 24 | * [Программа 17.9 (расширенная). Реализация АДТ графа (списки смежных вершин)](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/SparseMultiGRAPH.cc) 25 | * [Программа 17.10. Итератор для представления графа в виде списка смежных вершин](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/SparseMultiGRAPH.cc) 26 | * [Программа 17.11. Реализация класса, определяющего степени вершин](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/DEGREE.cc) 27 | * [Программа 17.12. Генератор случайных графов (случайные рёбра)](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/IO.cc) 28 | * [Программа 17.13. Генератор случайных графов (случайный граф)](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/IO.cc) 29 | * [Программа 17.14. Построение графа из пар символов](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/IO.cc) 30 | * [Программа 17.15. Символьная индексация имён вершин](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/ST.cc) 31 | * [Программа 17.16. Поиск простого пути](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/sPATH.cc) 32 | * [Программа 17.17. Гамильтонов путь](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/gPATH.cc) 33 | * [Программа 17.18. Существование эйлерова цикла](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/ePATH.cc) 34 | * [Программа 17.19 (обновлённая). Поиск эйлерова пути с линейным временем выполнения](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/ePATH.cc) 35 | * [Программа 18.1. Поиск в глубину связной компоненты](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/cDFS.cc) 36 | * [Программа 18.2. Поиск на графе](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/SEARCH.cc) 37 | * [Программа 18.3. Производный класс поиска в глубину](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/DFS.cc) 38 | * [Программа 18.5. Двухпроходный эйлеров цикл](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/EULER.cc) 39 | * [Программа 18.6. Раскраска графа в два цвета (двудольные графы)](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/BI.cc) 40 | * [Программа 18.7. Ребёрная связность](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/EC.cc) 41 | * [Программа 18.8. Поиск в ширину](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/BFS.cc) 42 | * [Программа 18.9. Усовершенствованный алгоритм BFS](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/BFS.cc) 43 | * [Программа 18.10. Обобщённый поиск на графе](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/PFS.cc) 44 | * [Программа 18.11. Реализация рандомизированной очереди](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/GQ.cc) 45 | * [Программа 19.1. Обращение орграфа](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/clients.cc) 46 | * [Программа 19.2. DFS на орграфе](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/InfoDFS.cc) 47 | * [Программа 19.3. Алгоритм Уоршала](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/TC.cc) 48 | * [Программа 19.4. Транзитивное замыкание, построенное на основе поиска в глубину](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/tc.cc) 49 | * [Программа 19.6. Обратная топологическая сортировка](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/dagTSs.cc) 50 | * [Программа 19.7. Топологическая сортировка](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/dagTSr.cc) 51 | * [Программа 19.8. Топологическая сортировка основанная на очереди истоков](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/dagTSq.cc) 52 | * [Программа 19.9. Транзитивное замыкание графа DAG](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/dagTC.cc) 53 | * [Программа 19.10. Сильные компоненты (алгоритм Косорайю)](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/SCc.cc) 54 | * [Программа 19.11. Сильные компоненты (алгоритм Тарьяна)](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/SCt.cc) 55 | * [Программа 19.12. Сильные компоненты (алгоритм Габова)](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/SCg.cc) 56 | * [Программа 19.13. Транзитивное замыкание на основе сильных компонент](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/TCsc.cc) 57 | * [Программа 20.1. Интерфейс АДТ взвешенного ребра](https://github.com/newmen/graph-algorithms/blob/master/cpp/second_half/EDGE.cc) 58 | * [Программа 20.1. Интерфейс АДТ графа со взвешенными рёбрами](https://github.com/newmen/graph-algorithms/blob/master/cpp/second_half/GRAPH.cc) 59 | * [Программа 20.2. Пример клиентской функции обработки графа](https://github.com/newmen/graph-algorithms/blob/master/cpp/second_half/clients.cc) 60 | * [Программа 20.3 (обновлённая). Класс взвешенного графа (представление в виде матрицы смежности)](https://github.com/newmen/graph-algorithms/blob/master/cpp/second_half/DenseGRAPH.cc) 61 | * [Программа 20.4. Класс итератора, ориентированный на представление графа в виде матрицы смежности](https://github.com/newmen/graph-algorithms/blob/master/cpp/second_half/DenseGRAPH.cc) 62 | * [Программа 20.5. Класс взвешенного графа (списки смежных вершин)](https://github.com/newmen/graph-algorithms/blob/master/cpp/second_half/SparseMultiGRAPH.cc) 63 | * [Программа 20.6. Алгоритм Прима, реализующий построение дерева MST](https://github.com/newmen/graph-algorithms/blob/master/cpp/second_half/MSTpr.cc) 64 | * [Программа 20.8 (обновлённая). Алгоритм Крускала, обеспечивающий построение дерева MST](https://github.com/newmen/graph-algorithms/blob/master/cpp/second_half/MSTcr.cc) 65 | * [Программа 20.9. Алгоритм Борувки построения дерева MST](https://github.com/newmen/graph-algorithms/blob/master/cpp/second_half/MSTbr.cc) 66 | * [Программа 20.10. Реализация очереди с приоритетами в виде многопозиционного частично упорядоченного полного дерева](https://github.com/newmen/graph-algorithms/blob/master/cpp/second_half/PQi.cc) 67 | 68 | ### Упражнения 69 | 70 | * [vector deg; Упражнение 17.42](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/DenseGRAPH.cc) 71 | * [Упражнение 17.12](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/IO.cc) 72 | * [Упражнение 17.13](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/clients.cc) 73 | * [Упражнение 17.14](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/IO.cc) 74 | * [Упражнение 17.18](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/IO.cc) 75 | * [Упражнение 17.20](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/GRAPH.cc) 76 | * [Упражнение 17.20](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/DenseGRAPH.cc) 77 | * [Упражнение 17.22](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/UndirDenseGRAPH.cc) 78 | * [Упражнение 17.23](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/UndirBitDenseGRAPH.cc) 79 | * [Упражнение 17.26](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/clients.cc) 80 | * [Упражнение 17.28](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/SparseGRAPH.cc) 81 | * [Упражнение 17.28](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/SparseMultiGRAPH.cc) 82 | * [Упражнение 17.29](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/SparseGRAPH.cc) 83 | * [Упражнение 17.29](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/SparseMultiGRAPH.cc) 84 | * [Упражнение 17.30](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/STLSparseMultiGRAPH.cc) 85 | * [Упражнение 17.34](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/DenseGRAPH.cc) 86 | * [Упражнение 17.34](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/STLSparseMultiGRAPH.cc) 87 | * [Упражнение 17.34](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/SparseMultiGRAPH.cc) 88 | * [Упражнение 17.34](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/GRAPH.cc) 89 | * [Упражнение 17.34](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/UndirBitDenseGRAPH.cc) 90 | * [Упражнение 17.34](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/SparseGRAPH.cc) 91 | * [Упражнение 17.34](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/UndirDenseGRAPH.cc) 92 | * [Упражнение 17.35](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/SparseGRAPH.cc) 93 | * [Упражнение 17.36 (обновлённое)](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/clients.cc) 94 | * [Упражнение 17.39](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/DenseMultiGRAPH.cc) 95 | * [Упражнение 17.42](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/DenseGRAPH.cc) 96 | * [Упражнение 17.43](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/SparseMultiGRAPH.cc) 97 | * [Упражнение 17.44](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/SparseMultiGRAPH.cc) 98 | * [Упражнение 17.44](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/DenseGRAPH.cc) 99 | * [Упражнение 17.44](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/clients.cc) 100 | * [Упражнение 17.46, 17.49](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/EdgeOptimalSparseGRAPH.cc) 101 | * [Упражнение 17.47](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/EdgeOptimalSparseGRAPH.cc) 102 | * [Упражнение 17.51](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/StaticGRAPH.cc) 103 | * [Упражнение 17.52](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/StaticMultiGRAPH.cc) 104 | * [Упражнение 17.53](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/StaticMultiGRAPH.cc) 105 | * [Упражнение 17.63](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/MapST.cc) 106 | * [Упражнение 17.65, 17.66](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/main.cpp) 107 | * [Упражнение 18.13, 18.14, 18.17](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/InfoDFS.cc) 108 | * [Упражнение 18.52](https://github.com/newmen/graph-algorithms/blob/master/cpp/first_half/BFS.cc) 109 | * [Упражнение 20.8](https://github.com/newmen/graph-algorithms/blob/master/cpp/second_half/WeightedEdge.cc) 110 | * [Упражнение 20.9](https://github.com/newmen/graph-algorithms/blob/master/cpp/second_half/IO.cc) -------------------------------------------------------------------------------- /contents.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | def get_contents(comment_begin) 4 | uses = `grep -r "#{comment_begin}" cpp`.chomp.split("\n") 5 | uses.map do |use| 6 | filename, comment = use.split(':', 2) 7 | num = comment.dup.strip 8 | num["// #{comment_begin} "] = '' 9 | num, _ = num.split(' ', 2) 10 | fnum, snum = num.split('.') 11 | comment['//'] = '' 12 | [fnum.to_i, snum.to_i, comment.strip, filename] 13 | end 14 | end 15 | 16 | def sort_contents(contents) 17 | contents.sort do |a, b| 18 | a[0] != b[0] ? a[0] <=> b[0] : a[1] <=> b[1] 19 | end 20 | end 21 | 22 | def repo_url 23 | return @repo_url if @repo_url 24 | own_url = `git config --get remote.origin.url`.chomp 25 | user_repo = own_url.match(':(.*)\.git')[1] 26 | @repo_url = "https://github.com/#{user_repo}" 27 | end 28 | 29 | def link_to(title, filename) 30 | "[#{title}](#{repo_url}/blob/master/#{filename})" 31 | end 32 | 33 | def make_contents(contents) 34 | sort_contents(contents).map do |_, _, comment, filename| 35 | "* #{link_to(comment, filename)}" 36 | end.join("\n") 37 | end 38 | 39 | program_contets = make_contents(get_contents('Программа')) 40 | issue_contets = make_contents(get_contents('Упражнение')) 41 | 42 | File.open('contents.md', 'w') do |f| 43 | f.write("### Программы из текста\n\n") 44 | f.write(program_contets) 45 | 46 | f.write("\n\n### Упражнения\n\n") 47 | f.write(issue_contets) 48 | end 49 | -------------------------------------------------------------------------------- /cpp/first_half/BFS.cc: -------------------------------------------------------------------------------- 1 | #ifndef BFS_CC_ 2 | #define BFS_CC_ 3 | 4 | #include 5 | #include "SEARCH.cc" 6 | using namespace std; 7 | 8 | // Упражнение 18.52 9 | template 10 | class BFS : public SEARCH { 11 | vector st; 12 | 13 | // Программа 18.8. Поиск в ширину 14 | void notOptimal(Edge e) { 15 | queue Q; 16 | Q.push(e); 17 | while (!Q.empty()) { 18 | e = Q.front(); 19 | Q.pop(); 20 | if (this->ord[e.w] == -1) { 21 | int v = e.v, w = e.w; 22 | this->ord[w] = this->cnt++; 23 | st[w] = v; 24 | typename Graph::adjIterator A(this->G, w); 25 | for (int t = A.beg(); !A.end(); t = A.nxt()) { 26 | if (this->ord[t] == -1) Q.push(Edge(w, t)); 27 | } 28 | } 29 | } 30 | } 31 | 32 | // Программа 18.9. Усовершенствованный алгоритм BFS 33 | void optimal(Edge e) { 34 | queue Q; 35 | Q.push(e); 36 | this->ord[e.w] = this->cnt++; 37 | while (!Q.empty()) { 38 | e = Q.front(); 39 | Q.pop(); 40 | st[e.w] = e.v; 41 | typename Graph::adjIterator A(this->G, e.w); 42 | for (int t = A.beg(); !A.end(); t = A.nxt()) { 43 | if (this->ord[t] == -1) { 44 | Q.push(Edge(e.w, t)); 45 | this->ord[t] = this->cnt++; 46 | } 47 | } 48 | } 49 | } 50 | 51 | void searchC(Edge e) { 52 | // notOptimal(e); 53 | optimal(e); 54 | } 55 | 56 | public: 57 | BFS(const Graph &G) : SEARCH(G), st(G.V(), -1) { 58 | this->search(); 59 | } 60 | 61 | int ST(int v) const { return st[v]; } 62 | }; 63 | 64 | #endif -------------------------------------------------------------------------------- /cpp/first_half/BI.cc: -------------------------------------------------------------------------------- 1 | #ifndef BI_CC 2 | #define BI_CC 3 | 4 | #include 5 | using namespace std; 6 | 7 | // Программа 18.6. Раскраска графа в два цвета (двудольные графы) 8 | template 9 | class BI { 10 | const Graph &G; 11 | bool OK; 12 | vector vc; 13 | 14 | bool dfsR(int v, int c) { 15 | vc[v] = (c + 1) % 2; 16 | typename Graph::adjIterator A(G, v); 17 | for (int t = A.beg(); !A.end(); t = A.nxt()) { 18 | if (vc[t] == -1) { 19 | if (!dfsR(t, vc[v])) return false; 20 | } else { 21 | if (vc[t] != c) return false; 22 | } 23 | } 24 | 25 | return true; 26 | } 27 | 28 | public: 29 | BI(const Graph &G) : G(G), OK(true), vc(G.V(), -1) { 30 | for (int v = 0; v < G.V(); v++) { 31 | if (vc[v] == -1) { 32 | if (!dfsR(v, 0)) { 33 | OK = false; 34 | return; 35 | } 36 | } 37 | } 38 | } 39 | 40 | bool bipartite() const { return OK; } 41 | int color(int v) const { return vc[v]; } 42 | }; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /cpp/first_half/CC.cc: -------------------------------------------------------------------------------- 1 | #ifndef CC_CC_ 2 | #define CC_CC_ 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | // Программа 17.5, 18.4. Интерфейс связности, Связность графа 9 | template 10 | class CC { 11 | const Graph &G; 12 | int ccnt; 13 | vector id; 14 | 15 | void ccR(int w) { 16 | id[w] = ccnt; 17 | typename Graph::adjIterator A(G, w); 18 | for (int v = A.beg(); !A.end(); v = A.nxt()) { 19 | if (id[v] == -1) ccR(v); 20 | } 21 | } 22 | 23 | public: 24 | CC(const Graph &) : G(G), ccnt(0), id(G.V(), -1) { 25 | for (int v = 0; v < G.V(); v++) { 26 | if (id[v] == -1) { 27 | ccR(v); 28 | ccnt++; 29 | } 30 | } 31 | } 32 | 33 | int count() const { return ccnt; } 34 | bool connect(int s, int t) { return id[s] == id[t]; } 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /cpp/first_half/DEGREE.cc: -------------------------------------------------------------------------------- 1 | #ifndef DEGREE_CC_ 2 | #define DEGREE_CC_ 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | // Программа 17.11. Реализация класса, определяющего степени вершин 9 | template 10 | class DEGREE { 11 | const Graph &G; 12 | vector degree; 13 | 14 | public: 15 | DEGREE(const Graph &G) : G(G), degree(G.V(), 0) { 16 | for (int v = 0; v < G.V(); v++) { 17 | typename Graph::adjIterator A(G, v); 18 | for (A.beg(); !A.end(); A.nxt()) ++degree[v]; 19 | } 20 | } 21 | 22 | int operator [] (int v) const { 23 | return degree[v]; 24 | } 25 | }; 26 | 27 | #endif -------------------------------------------------------------------------------- /cpp/first_half/DFS.cc: -------------------------------------------------------------------------------- 1 | #ifndef DFS_CC_ 2 | #define DFS_CC_ 3 | 4 | #include "SEARCH.cc" 5 | 6 | // Программа 18.3. Производный класс поиска в глубину 7 | template 8 | class DFS : public SEARCH { 9 | vector st; 10 | 11 | protected: 12 | void searchC(Edge e) { 13 | int w = e.w; 14 | this->ord[w] = this->cnt++; 15 | st[e.w] = e.v; 16 | typename Graph::adjIterator A(this->G, w); 17 | for (int t = A.beg(); !A.end(); t = A.nxt()) { 18 | if (this->ord[t] == -1) searchC(Edge(w, t)); 19 | } 20 | } 21 | 22 | public: 23 | DFS(const Graph &G) : SEARCH(G), st(G.V(), -1) { 24 | this->search(); 25 | } 26 | 27 | int ST(int v) const { return st[v]; } 28 | }; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /cpp/first_half/DenseGRAPH.cc: -------------------------------------------------------------------------------- 1 | #ifndef DENSEGRAPH_H_ 2 | #define DENSEGRAPH_H_ 3 | 4 | #include 5 | #include "Edge.cc" 6 | 7 | using namespace std; 8 | 9 | // Программа 17.7 (расширенная). Реализация АДТ графа (матрица смежности) 10 | class DenseGRAPH { 11 | int Vcnt, Ecnt; 12 | bool digraph; 13 | vector< vector > adj; 14 | vector deg; // Упражнение 17.42 15 | 16 | public: 17 | DenseGRAPH(int V, bool digraph = false) : 18 | Vcnt(V), Ecnt(0), digraph(digraph), adj(V), deg(V, -1) 19 | { 20 | for (int i = 0; i < V; i++) adj[i].assign(V, false); 21 | } 22 | 23 | int V() const { return Vcnt; } 24 | int E() const { return Ecnt; } 25 | bool directed() const { return digraph; } 26 | 27 | void insert(Edge e) { 28 | int v = e.v, w = e.w; 29 | if (adj[v][w] == false) Ecnt++; 30 | adj[v][w] = true; 31 | if (!digraph) adj[w][v] = true; 32 | } 33 | 34 | void remove(Edge e) { 35 | int v = e.v, w = e.w; 36 | if (adj[v][w] == true) Ecnt--; 37 | adj[v][w] = false; 38 | if (!digraph) adj[w][v] = false; 39 | } 40 | 41 | bool edge(int v, int w) const { 42 | return adj[v][w]; 43 | } 44 | 45 | // Упражнение 17.20 46 | void insert() { 47 | for (int v = 0; v < Vcnt; ++v) { 48 | adj[v].push_back(false); 49 | } 50 | adj.push_back(vector(++Vcnt, false)); 51 | deg.push_back(-1); 52 | } 53 | void remove(int v) { 54 | vector< vector >::iterator row = adj.begin() + v; 55 | for (vector::const_iterator p = row->begin(); p != row->end(); ++p) { 56 | if (*p) --Ecnt; 57 | } 58 | adj.erase(row); 59 | 60 | for (row = adj.begin(); row != adj.end(); ++row) { 61 | vector::iterator p = row->begin() + v; 62 | row->erase(p); 63 | } 64 | --Vcnt; 65 | 66 | deg.erase(deg.begin() + v); 67 | } 68 | 69 | // Упражнение 17.34 70 | void removeLoopsAndParallels() { 71 | for (int v = 0; v < Vcnt; ++v) { 72 | if (adj[v][v]) --Ecnt; 73 | adj[v][v] = false; 74 | } 75 | } 76 | 77 | // Упражнение 17.42 78 | int degree(int v) { 79 | if (deg[v] == -1) { 80 | deg[v] = 0; 81 | for (int i = 0; i < Vcnt; ++i) { 82 | if (adj[v][i]) ++deg[v]; 83 | } 84 | } 85 | return deg[v]; 86 | } 87 | 88 | // Упражнение 17.44 89 | int zeros() const { 90 | int n = 0; 91 | bool bonded; 92 | for (int v = 0; v < Vcnt; ++v) { 93 | bonded = false; 94 | for (int w = 0; w < Vcnt; ++w) { 95 | if (!adj[v][w]) continue; 96 | bonded = true; 97 | break; 98 | } 99 | if (!bonded) ++n; 100 | } 101 | return n; 102 | } 103 | 104 | class adjIterator; 105 | friend class adjIterator; 106 | }; 107 | 108 | // Программа 17.8. Итератор для представления матрицы смежности 109 | class DenseGRAPH::adjIterator { 110 | const DenseGRAPH &G; 111 | int v, i; 112 | 113 | public: 114 | adjIterator(const DenseGRAPH &G, int v) : G(G), v(v), i(-1) {} 115 | 116 | int beg() { 117 | i = -1; 118 | return nxt(); 119 | } 120 | 121 | int nxt() { 122 | for (i++; i < G.V(); i++) { 123 | if (G.adj[v][i] == true) return i; 124 | } 125 | return -1; 126 | } 127 | 128 | bool end() { 129 | return i >= G.V(); 130 | } 131 | }; 132 | 133 | #endif 134 | -------------------------------------------------------------------------------- /cpp/first_half/DenseMultiGRAPH.cc: -------------------------------------------------------------------------------- 1 | #ifndef DENSEMULTIGRAPH_H_ 2 | #define DENSEMULTIGRAPH_H_ 3 | 4 | #include 5 | #include "Edge.cc" 6 | 7 | using namespace std; 8 | 9 | // Упражнение 17.39 10 | class DenseMultiGRAPH { 11 | public: 12 | class adjIterator; 13 | friend class adjIterator; 14 | 15 | DenseMultiGRAPH(int V, bool digraph = false) : 16 | Vcnt(V), Ecnt(0), digraph(digraph), adj(V) 17 | { 18 | for (int i = 0; i < V; i++) adj[i].assign(V, 0); 19 | } 20 | 21 | int V() const { return Vcnt; } 22 | int E() const { return Ecnt; } 23 | bool directed() const { return digraph; } 24 | 25 | void insert(Edge e) { 26 | int v = e.v, w = e.w; 27 | ++adj[v][w]; 28 | if (!digraph && v != w) ++adj[w][v]; 29 | ++Ecnt; 30 | } 31 | 32 | void remove(Edge e) { 33 | int v = e.v, w = e.w; 34 | if (adj[v][w] > 0) { 35 | --adj[v][w]; 36 | if (!digraph && v != w) --adj[w][v]; 37 | --Ecnt; 38 | } 39 | } 40 | 41 | bool edge(int v, int w) const { 42 | return adj[v][w]; 43 | } 44 | 45 | void insert() { 46 | for (vector< vector >::iterator p = adj.begin(); p != adj.end(); ++p) { 47 | p->push_back(0); 48 | } 49 | adj.push_back(vector(++Vcnt, 0)); 50 | } 51 | 52 | void remove(int v) { 53 | vector< vector >::iterator row = adj.begin() + v; 54 | for (vector::const_iterator p = row->begin(); p != row->end(); ++p) { 55 | Ecnt -= *p; 56 | } 57 | adj.erase(row); 58 | 59 | for (row = adj.begin(); row != adj.end(); ++row) { 60 | vector::iterator p = row->begin() + v; 61 | row->erase(p); 62 | } 63 | --Vcnt; 64 | } 65 | 66 | void removeLoopsAndParallels() { 67 | for (int v = 0; v < Vcnt; ++v) { 68 | Ecnt -= adj[v][v]; 69 | adj[v][v] = 0; 70 | 71 | for (int w = 0; w < Vcnt; ++w) { 72 | if (adj[v][w] < 2) continue; 73 | remove(Edge(v, w)); 74 | } 75 | } 76 | } 77 | 78 | private: 79 | int Vcnt, Ecnt; 80 | bool digraph; 81 | vector< vector > adj; 82 | }; 83 | 84 | class DenseMultiGRAPH::adjIterator { 85 | public: 86 | adjIterator(const DenseMultiGRAPH &G, int v) : G(G), v(v), i(0), inner(0) {} 87 | 88 | int beg() { 89 | i = 0; 90 | inner = 0; 91 | return nxt(); 92 | } 93 | 94 | int nxt() { 95 | if (i < G.V() && inner++ < G.adj[v][i]) { 96 | return i; 97 | } else { 98 | for (++i; i < G.V(); ++i) { 99 | if (G.adj[v][i] == 0) continue; 100 | inner = 1; 101 | return i; 102 | } 103 | return -1; 104 | } 105 | } 106 | 107 | bool end() { 108 | return i >= G.V(); 109 | } 110 | 111 | private: 112 | const DenseMultiGRAPH &G; 113 | int v, i, inner; 114 | }; 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /cpp/first_half/EC.cc: -------------------------------------------------------------------------------- 1 | #ifndef EC_CC_ 2 | #define EC_CC_ 3 | 4 | #include "SEARCH.cc" 5 | 6 | // Программа 18.7. Ребёрная связность 7 | template 8 | class EC : public SEARCH { 9 | int bcnt; 10 | vector low; 11 | 12 | void searchR(Edge e) { 13 | int w = e.w; 14 | this->ord[w] = this->cnt++; 15 | low[w] = this->ord[w]; 16 | 17 | typename Graph::adjIterator A(this->G, w); 18 | for (int t = A.beg(); !A.end(); t = A.nxt()) { 19 | if (this->ord[t] == -1) { 20 | searchR(Edge(w, t)); 21 | if (low[w] > low[t]) low[w] = low[t]; 22 | if (low[t] == this->ord[t]) bcnt++; // новый мост 23 | } else if (t != e.v) { 24 | if (low[w] > this->ord[t]) low[w] = this->ord[t]; 25 | } 26 | } 27 | } 28 | 29 | public: 30 | EC(const Graph &G) : SEARCH(G), bcnt(0), low(G.V(), -1) { 31 | this->search(); 32 | } 33 | 34 | int count() const { return bcnt + 1; } 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /cpp/first_half/EULER.cc: -------------------------------------------------------------------------------- 1 | #ifndef EULER_CC_ 2 | #define EULER_CC_ 3 | 4 | #include 5 | #include "SEARCH.cc" 6 | 7 | using namespace std; 8 | 9 | // Программа 18.5. Двухпроходный эйлеров цикл 10 | template 11 | class EULER : public SEARCH { 12 | void searchC(Edge e) { 13 | int v = e.v, w = e.w; 14 | this->ord[w] = this->cnt++; 15 | cout << "-" << w; 16 | 17 | typename Graph::adjIterator A(this->G, w); 18 | for (int t = A.beg(); !A.end(); t = A.nxt()) { 19 | if (this->ord[t] == -1) searchC(Edge(w, t)); 20 | else if (this->ord[t] < this->ord[v]) { 21 | cout << "-" << t << "-" << w; 22 | } 23 | } 24 | 25 | if (v != w) cout << "-" << v; 26 | else cout << endl; 27 | } 28 | 29 | public: 30 | EULER(const Graph &G) : SEARCH(G) { 31 | this->search(); 32 | } 33 | 34 | }; 35 | 36 | #endif -------------------------------------------------------------------------------- /cpp/first_half/Edge.cc: -------------------------------------------------------------------------------- 1 | #ifndef EDGE_CC_ 2 | #define EDGE_CC_ 3 | 4 | // Программа 17.1. Интерфейс ребра графа 5 | struct Edge { 6 | int v, w; 7 | Edge(int v = -1, int w = -1) : v(v), w(w) {} 8 | }; 9 | 10 | #endif -------------------------------------------------------------------------------- /cpp/first_half/EdgeOptimalSparseGRAPH.cc: -------------------------------------------------------------------------------- 1 | #ifndef EDGEOPTIMALSPARSEGRAPH_CC_ 2 | #define EDGEOPTIMALSPARSEGRAPH_CC_ 3 | 4 | #include 5 | #include 6 | #include "Edge.cc" 7 | 8 | using namespace std; 9 | 10 | // Упражнение 17.46, 17.49 11 | 12 | #define HASH_T int 13 | 14 | class EdgeOptimalSparseGRAPH { 15 | struct node { 16 | int v; 17 | node *next, *prev; 18 | node(int x, node *t) : v(x), next(t), prev(0) {} 19 | }; 20 | 21 | typedef node * link; 22 | 23 | public: 24 | class adjIterator; 25 | friend class adjIterator; 26 | 27 | EdgeOptimalSparseGRAPH(int V, bool digraph = false) : 28 | Vcnt(V), Ecnt(0), digraph(digraph), adj(V) 29 | { 30 | link t = 0; 31 | adj.assign(V, t); 32 | } 33 | 34 | EdgeOptimalSparseGRAPH(const EdgeOptimalSparseGRAPH &G) : 35 | Vcnt(G.V()), Ecnt(G.E()), digraph(G.directed()), adj(G.V()) 36 | { 37 | for (int i = 0; i < Vcnt; ++i) { 38 | link t = G.adj[i]; 39 | while (t) { 40 | simpleInsert(i, t->v); 41 | t = t->next; 42 | } 43 | } 44 | } 45 | 46 | ~EdgeOptimalSparseGRAPH() { 47 | for (vector::iterator p = adj.begin(); p != adj.end(); ++p) { 48 | link t = *p, pv; 49 | while (t) { 50 | pv = t; 51 | t = t->next; 52 | delete pv; 53 | } 54 | } 55 | } 56 | 57 | int V() const { return Vcnt; } 58 | int E() const { return Ecnt; } 59 | bool directed() const { return digraph; } 60 | 61 | void insert(Edge e) { 62 | int v = e.v, w = e.w; 63 | if (v == w || edge(v, w)) return; 64 | 65 | simpleInsert(v, w); 66 | if (!digraph) simpleInsert(w, v); 67 | 68 | ++Ecnt; 69 | } 70 | 71 | void remove(Edge e) { 72 | int v = e.v, w = e.w; 73 | if (!edge(v, w)) return; 74 | 75 | simpleRemove(v, w); 76 | if (!digraph) simpleRemove(w, v); 77 | 78 | --Ecnt; 79 | } 80 | 81 | bool edge(int v, int w) const { 82 | return edges.find(hashf(v, w)) != edges.end(); 83 | } 84 | 85 | void insert() { 86 | link t = 0; 87 | adj.push_back(t); 88 | ++Vcnt; 89 | } 90 | 91 | // Упражнение 17.47 92 | void remove(int v) { 93 | link t = adj[v], backup; 94 | while (t) { 95 | edges.erase(edges.find(hashf(v, t->v))); 96 | backup = t; 97 | t = t->next; 98 | delete backup; 99 | --Ecnt; 100 | } 101 | adj.erase(adj.begin() + v); 102 | --Vcnt; 103 | 104 | link *pt; 105 | for (int a, i = 0; i < Vcnt; ++i) { 106 | a = (i < v) ? i : i + 1; 107 | pt = &adj[i]; 108 | while (*pt) { 109 | if ((*pt)->v == v) { 110 | edges.erase(edges.find(hashf(a, (*pt)->v))); 111 | backup = (*pt)->next; 112 | delete *pt; 113 | *pt = backup; 114 | if (digraph) --Ecnt; 115 | } else { 116 | if (a != i || (*pt)->v > v) { 117 | edges.erase(edges.find(hashf(a, (*pt)->v))); 118 | } 119 | if ((*pt)->v > v) { 120 | --(*pt)->v; 121 | } 122 | if (a != i || (*pt)->v > v) { 123 | edges[hashf(i, (*pt)->v)] = *pt; 124 | } 125 | pt = &(*pt)->next; 126 | } 127 | } 128 | } 129 | } 130 | 131 | void removeLoopsAndParallels() {} 132 | 133 | private: 134 | void simpleInsert(int v, int w) { 135 | link pv = adj[v]; 136 | adj[v] = new node(w, pv); 137 | if (pv) pv->prev = adj[v]; 138 | edges[hashf(v, w)] = adj[v]; 139 | } 140 | 141 | void simpleRemove(int v, int w) { 142 | map::iterator pt = edges.find(hashf(v, w)); 143 | link t = pt->second; 144 | if (t->prev) t->prev->next = t->next; 145 | if (t->next) t->next->prev = t->prev; 146 | if (!t->prev && !t->next) adj[v] = 0; 147 | delete t; 148 | edges.erase(pt); 149 | } 150 | 151 | HASH_T hashf(int v, int w) const { 152 | return (v << 19) | (w << 7); 153 | } 154 | 155 | private: 156 | int Vcnt, Ecnt; 157 | bool digraph; 158 | vector adj; 159 | map edges; 160 | }; 161 | 162 | class EdgeOptimalSparseGRAPH::adjIterator { 163 | const EdgeOptimalSparseGRAPH &G; 164 | int v; 165 | link t; 166 | 167 | public: 168 | adjIterator(const EdgeOptimalSparseGRAPH &G, int v) : G(G), v(v), t(0) {} 169 | 170 | int beg() { 171 | t = G.adj[v]; 172 | return t ? t->v : -1; 173 | } 174 | 175 | int nxt() { 176 | if (t) t = t->next; 177 | return t ? t->v : -1; 178 | } 179 | 180 | bool end() { 181 | return t == 0; 182 | } 183 | }; 184 | 185 | #endif 186 | -------------------------------------------------------------------------------- /cpp/first_half/EdgeSorter.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "EdgeSorter.h" 3 | 4 | vector sortEdges(const vector &edges) { 5 | vector sortedEdges = edges; 6 | sort(sortedEdges.begin(), sortedEdges.end(), EdgeSorter()); 7 | return sortedEdges; 8 | } 9 | -------------------------------------------------------------------------------- /cpp/first_half/EdgeSorter.h: -------------------------------------------------------------------------------- 1 | #ifndef EDGESORTER_H_ 2 | #define EDGESORTER_H_ 3 | 4 | #include 5 | #include "Edge.cc" 6 | 7 | using namespace std; 8 | 9 | struct EdgeSorter { 10 | bool operator () (const Edge &a, const Edge &b) { 11 | if (a.v == b.v && a.w == b.w) return true; 12 | return (a.v <= b.v && a.w < b.w); 13 | } 14 | }; 15 | 16 | vector sortEdges(const vector &edges); 17 | 18 | #endif -------------------------------------------------------------------------------- /cpp/first_half/GQ.cc: -------------------------------------------------------------------------------- 1 | #ifndef GQ_CC_ 2 | #define GQ_CC_ 3 | 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | // Программа 18.11. Реализация рандомизированной очереди 9 | template 10 | class GQ { 11 | private: 12 | vector s; 13 | int N; 14 | 15 | public: 16 | GQ(int maxN) : s(maxN + 1), N(0) {} 17 | 18 | int empty() const { return N == 0; } 19 | void put(Item item) { s[N++] = item; } 20 | void update(Item x) {} 21 | Item get() { 22 | int i = int(N * rand() / (1.0 + RAND_MAX)); 23 | Item t = s[i]; 24 | s[i] = s[N - 1]; 25 | s[N - 1] = t; 26 | return s[--N]; 27 | } 28 | }; 29 | 30 | #endif 31 | 32 | -------------------------------------------------------------------------------- /cpp/first_half/GRAPH.cc: -------------------------------------------------------------------------------- 1 | #ifndef GRAPH_CC_ 2 | #define GRAPH_CC_ 3 | 4 | #include "Edge.cc" 5 | 6 | // Программа 17.1 (расширеная). Интерфейс АДТ графа 7 | class GRAPH { 8 | private: 9 | public: 10 | GRAPH(int, bool); 11 | ~GRAPH(); 12 | 13 | int V() const; 14 | int E() const; 15 | bool directed() const; 16 | 17 | void insert(Edge); 18 | void remove(Edge); 19 | bool edge(int, int) const; 20 | 21 | // Упражнение 17.20 22 | void insert(); // Добавления новой вершины 23 | void remove(int); // Удаление вершины 24 | 25 | // Упражнение 17.34 26 | void removeLoopsAndParallels(); 27 | 28 | class adjIterator { 29 | public: 30 | adjIterator(const GRAPH &, int); 31 | int beg(); 32 | int nxt(); 33 | bool end(); 34 | }; 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /cpp/first_half/IO.cc: -------------------------------------------------------------------------------- 1 | #ifndef IO_CC_ 2 | #define IO_CC_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "Edge.cc" 8 | #include "ST.cc" 9 | // #include "MapST.cc" 10 | // typedef MapST ST; 11 | #include "clients.cc" 12 | 13 | using namespace std; 14 | 15 | // Программа 17.4 (расширенная). Интерфейс ввода/вывода для функций обработки графов 16 | template 17 | class IO { 18 | public: 19 | static void show(const Graph &G); 20 | static void showEdges(const Graph &G); 21 | static void showAdj(const Graph &G); 22 | 23 | static void scanEZ(Graph &G); 24 | static void scan(Graph &G); 25 | 26 | static void randE(Graph &G, int E); 27 | static void randG(Graph &G, int E); 28 | 29 | private: 30 | static bool isTerminateInput(int deep = 2); 31 | }; 32 | 33 | // Программа 17.3. Клиентская функция печати графа 34 | template 35 | void IO::show(const Graph &G) { 36 | for (int s = 0; s < G.V(); s++) { 37 | cout.width(2); 38 | cout << s << ": "; 39 | typename Graph::adjIterator A(G, s); 40 | for (int t = A.beg(); !A.end(); t = A.nxt()) { 41 | if (t == -1) continue; 42 | cout.width(2); 43 | cout << t << " "; 44 | } 45 | cout << endl; 46 | } 47 | cout << endl; 48 | } 49 | 50 | // Упражнение 17.14 51 | template 52 | void IO::showEdges(const Graph &G) { 53 | const vector vec = edges(G); 54 | for (vector::const_iterator p = vec.begin(); p != vec.end(); ++p) { 55 | cout << p->v << "-" << p->w << " "; 56 | } 57 | cout << '\n' << endl; 58 | } 59 | 60 | // Упражнение 17.18 61 | template 62 | void IO::showAdj(const Graph &G) { 63 | const int DEFAULT_WIDTH = (G.V() < 11) ? 2 : 3; 64 | 65 | for (int i = 0; i < DEFAULT_WIDTH; i++) cout << ' '; 66 | cout << " |"; 67 | for (int i = 0; i < G.V(); i++) { 68 | cout.width(DEFAULT_WIDTH); 69 | cout << i; 70 | } 71 | cout << endl; 72 | for (int i = 0; i <= G.V(); i++) { 73 | for (int j = 0; j < DEFAULT_WIDTH; j++) cout << '-'; 74 | } 75 | cout << "--" << endl; 76 | 77 | for (int v = 0; v < G.V(); v++) { 78 | cout.width(DEFAULT_WIDTH); 79 | cout << v << " |"; 80 | 81 | for (int w = 0; w < G.V(); w++) { 82 | cout.width(DEFAULT_WIDTH); 83 | cout << G.edge(v, w); 84 | } 85 | cout << endl; 86 | } 87 | cout << endl; 88 | } 89 | 90 | // Упражнение 17.12 91 | template 92 | bool IO::isTerminateInput(int deep) { 93 | if (deep == 0) return true; 94 | char c = cin.get(); 95 | if (c == '\n') return isTerminateInput(deep - 1); 96 | else cin.putback(c); 97 | return false; 98 | } 99 | template 100 | void IO::scanEZ(Graph &G) { 101 | int v, w; 102 | while (true) { 103 | if (isTerminateInput()) break; 104 | 105 | cin >> v >> w; 106 | if (v < 0 || v >= G.V() || w < 0 || w >= G.V()) { 107 | cerr << "Out of range" << endl; 108 | continue; 109 | } 110 | G.insert(Edge(v, w)); 111 | } 112 | } 113 | 114 | // Программа 17.14. Построение графа из пар символов 115 | template 116 | void IO::scan(Graph &G) { 117 | string v, w; 118 | ST st; 119 | while (true) { 120 | if (isTerminateInput()) break; 121 | 122 | cin >> v >> w; 123 | G.insert(Edge(st.index(v), st.index(w))); 124 | } 125 | } 126 | 127 | // Программа 17.12. Генератор случайных графов (случайные рёбра) 128 | template 129 | void IO::randE(Graph &G, int E) { 130 | int v, w; 131 | for (int i = 0; i < E; ++i) { 132 | v = rand() % G.V(); 133 | w = rand() % G.V(); 134 | G.insert(Edge(v, w)); 135 | } 136 | } 137 | 138 | // Программа 17.13. Генератор случайных графов (случайный граф) 139 | template 140 | void IO::randG(Graph &G, int E) { 141 | double p = 2.0 * E / G.V() / (G.V() - 1); 142 | for (int i = 0; i < G.V(); i++) { 143 | for (int j = 0; j < i; j++) { 144 | if (rand() < p * RAND_MAX) G.insert(Edge(i, j)); 145 | } 146 | } 147 | } 148 | 149 | #endif 150 | -------------------------------------------------------------------------------- /cpp/first_half/InfoDFS.cc: -------------------------------------------------------------------------------- 1 | #ifndef INFODFS_CC_ 2 | #define INFODFS_CC_ 3 | 4 | #include 5 | #include "SEARCH.cc" 6 | 7 | // Упражнение 18.13, 18.14, 18.17 8 | 9 | template 10 | class InfoDFS : public SEARCH { 11 | vector st; 12 | int cntP, depth, wide; 13 | 14 | void eachVertex(int v) { 15 | printSeek(); 16 | cout << endl; 17 | } 18 | 19 | void eachEdge(const Edge &e) { 20 | printEdge(e); 21 | 22 | cout << left; 23 | cout.width(22); 24 | printEdgeType(e); 25 | 26 | cout << right; 27 | cout.width(20 - depth * 2); 28 | printVec(this->ord); 29 | cout << " "; 30 | printVec(st); 31 | 32 | cout << endl; 33 | } 34 | 35 | void printSeek() const { 36 | for (int i = 0; i < depth; ++i) cout << " "; 37 | } 38 | 39 | void printEdge(const Edge &e) const { 40 | printSeek(); 41 | cout << left; 42 | cout << e.v << '-'; 43 | cout.width(3); 44 | cout << e.w; 45 | } 46 | 47 | void printEdgeType(const Edge &e) const { 48 | if (this->ord[e.w] == -1) cout << "tree link"; 49 | else if (this->G.directed()) { 50 | if (st[e.w] == -1) cout << "back link"; 51 | else if (this->ord[e.w] > this->ord[e.v]) cout << "down link"; 52 | else cout << "cross link"; 53 | } else { 54 | if (st[e.v] == e.w) cout << "parent link"; 55 | else if (this->ord[e.w] < this->ord[e.v]) cout << "back link"; 56 | else cout << "down link"; 57 | } 58 | } 59 | 60 | void printVec(const vector &vec) const { 61 | for (vector::const_iterator p = vec.begin(); p != vec.end(); ++p) { 62 | if (p != vec.begin()) cout.width(wide); 63 | if (*p == -1) cout << "*"; 64 | else cout << *p; 65 | } 66 | } 67 | 68 | void printHead() const { 69 | cout.width(48 + wide); 70 | if (this->G.directed()) { 71 | cout << "pre:"; 72 | } else { 73 | cout << "ord:"; 74 | } 75 | cout.width(this->G.V() * wide + 4); 76 | if (this->G.directed()) { 77 | cout << "post:"; 78 | } else { 79 | cout << "ST:"; 80 | } 81 | cout << endl; 82 | 83 | cout.width(45 + wide); 84 | for (int i = 0; i < this->G.V(); ++i) { 85 | if (i > 0) cout.width(wide); 86 | cout << i; 87 | } 88 | cout.width(5); 89 | for (int i = 0; i < this->G.V(); ++i) { 90 | if (i > 0) cout.width(wide); 91 | cout << i; 92 | } 93 | cout << '\n' << endl; 94 | } 95 | 96 | protected: 97 | void searchC(Edge e) { 98 | int w = e.w; 99 | this->ord[e.w] = this->cnt++; 100 | st[e.w] = e.v; 101 | 102 | // eachVertex(w); 103 | 104 | typename Graph::adjIterator A(this->G, w); 105 | for (int t = A.beg(); !A.end(); t = A.nxt()) { 106 | Edge o(w, t); 107 | eachEdge(o); 108 | 109 | if (this->ord[t] == -1) { 110 | ++depth; 111 | searchC(o); 112 | } 113 | } 114 | --depth; 115 | } 116 | 117 | // Программа 19.2. DFS на орграфе 118 | void searchR(Edge e) { 119 | int w = e.w; 120 | eachEdge(e); 121 | this->ord[w] = this->cnt++; 122 | ++depth; 123 | 124 | typename Graph::adjIterator A(this->G, w); 125 | for (int t = A.beg(); !A.end(); t = A.nxt()) { 126 | Edge x(w, t); 127 | 128 | if (this->ord[t] == -1) searchR(x); 129 | else eachEdge(x); 130 | } 131 | 132 | st[w] = cntP++; 133 | --depth; 134 | } 135 | 136 | void search() { 137 | printHead(); 138 | for (int v = 0; v < this->G.V(); v++) { 139 | if (this->ord[v] == -1) { 140 | depth = 0; 141 | Edge e = Edge(v, v); 142 | if (this->G.directed()) { 143 | searchR(e); 144 | } else { 145 | eachEdge(e); 146 | searchC(e); 147 | } 148 | } 149 | } 150 | cout << endl; 151 | } 152 | 153 | public: 154 | InfoDFS(const Graph &G) : SEARCH(G), st(G.V(), -1), cntP(0), depth(0) { 155 | wide = G.V() < 10 ? 1 : 2; 156 | this->search(); 157 | } 158 | 159 | int ST(int v) const { return st[v]; } 160 | }; 161 | 162 | #endif 163 | -------------------------------------------------------------------------------- /cpp/first_half/MapST.cc: -------------------------------------------------------------------------------- 1 | #ifndef MAPST_CC_ 2 | #define MAPST_CC_ 3 | 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | // Упражнение 17.63 10 | class MapST { 11 | public: 12 | MapST() : N(0) {} 13 | 14 | int index(const string &s) { 15 | if (rel.find(s) == rel.end()) rel[s] = N++; 16 | return rel[s]; 17 | } 18 | 19 | private: 20 | map rel; 21 | int N; 22 | }; 23 | 24 | 25 | #endif -------------------------------------------------------------------------------- /cpp/first_half/PFS.cc: -------------------------------------------------------------------------------- 1 | #ifndef PFS_CC_ 2 | #define PFS_CC_ 3 | 4 | #include "SEARCH.cc" 5 | #include "GQ.cc" 6 | 7 | // Программа 18.10. Обобщённый поиск на графе 8 | template 9 | class PFS : public SEARCH { 10 | vector st; 11 | 12 | void searchC(Edge e) { 13 | GQ Q(this->G.V()); 14 | Q.put(e); 15 | this->ord[e.w] = this->cnt++; 16 | while (!Q.empty()) { 17 | e = Q.get(); 18 | st[e.w] = e.v; 19 | typename Graph::adjIterator A(this->G, e.w); 20 | for (int t = A.beg(); !A.end(); t = A.nxt()) { 21 | if (this->ord[t] == -1) { 22 | Q.put(Edge(e.w, t)); 23 | this->ord[t] = this->cnt++; 24 | } else if (st[t] == -1) { 25 | Q.update(Edge(e.w, t)); 26 | } 27 | } 28 | } 29 | } 30 | 31 | public: 32 | PFS(const Graph &G) : SEARCH(G), st(G.V(), -1) { 33 | this->search(); 34 | } 35 | 36 | int ST(int v) const { return st[v]; } 37 | }; 38 | 39 | #endif -------------------------------------------------------------------------------- /cpp/first_half/SCc.cc: -------------------------------------------------------------------------------- 1 | #ifndef SCC_CC_ 2 | #define SCC_CC_ 3 | 4 | #include 5 | #include "clients.cc" 6 | using namespace std; 7 | 8 | // Программа 19.10. Сильные компоненты (алгоритм Косорайю) 9 | template 10 | class SCc { 11 | const Graph &G; 12 | int cnt, scnt; 13 | vector postI, postR, id; 14 | 15 | void dfsR(const Graph &G, int w) { 16 | id[w] = scnt; 17 | typename Graph::adjIterator A(G, w); 18 | for (int t = A.beg(); !A.end(); t = A.nxt()) { 19 | if (id[t] == -1) dfsR(G, t); 20 | } 21 | postI[cnt++] = w; 22 | } 23 | 24 | public: 25 | SCc(const Graph &G) : G(G), cnt(0), scnt(0), postI(G.V()), postR(G.V()), id(G.V(), -1) { 26 | Graph R(G.V(), true); 27 | reverse(G, R); 28 | for (int v = 0; v < R.V(); v++) { 29 | if (id[v] == -1) dfsR(R, v); 30 | } 31 | 32 | postR = postI; 33 | cnt = scnt = 0; 34 | id.assign(G.V(), -1); 35 | 36 | for (int v = G.V() - 1; v >= 0; v--) { 37 | if (id[postR[v]] == -1) { 38 | dfsR(G, postR[v]); 39 | scnt++; 40 | } 41 | } 42 | } 43 | 44 | int count() const { return scnt; } 45 | bool stronglyreachable(int v, int w) const { return id[v] == id[w]; } 46 | int ID(int v) const { return id[v]; } 47 | }; 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /cpp/first_half/SCg.cc: -------------------------------------------------------------------------------- 1 | #ifndef SCG_CC_ 2 | #define SCG_CC_ 3 | 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | // Программа 19.12. Сильные компоненты (алгоритм Габова) 9 | template 10 | class SCg { 11 | const Graph &G; 12 | stack S, path; 13 | int cnt, scnt; 14 | vector pre, id; 15 | 16 | void scR(int w) { 17 | pre[w] = cnt++; 18 | S.push(w); 19 | path.push(w); 20 | 21 | typename Graph::adjIterator A(G, w); 22 | for (int t = A.beg(); !A.end(); t = A.nxt()) { 23 | if (pre[t] == -1) scR(t); 24 | else if (id[t] == -1) { 25 | while (pre[path.top()] > pre[t]) path.pop(); 26 | } 27 | } 28 | 29 | if (path.top() == w) path.pop(); 30 | else return; 31 | 32 | int v; 33 | do { 34 | v = S.top(); 35 | S.pop(); 36 | id[v] = scnt; 37 | } while (v != w); 38 | scnt++; 39 | } 40 | 41 | public: 42 | SCg(const Graph &G) : G(G), cnt(0), scnt(0), pre(G.V(), -1), id(G.V(), -1) { 43 | for (int v = 0; v < G.V(); v++) { 44 | if (pre[v] == -1) scR(v); 45 | } 46 | } 47 | 48 | int count() const { return scnt; } 49 | bool stronglyreachable(int v, int w) const { return id[v] == id[w]; } 50 | int ID(int v) const { return id[v]; } 51 | }; 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /cpp/first_half/SCt.cc: -------------------------------------------------------------------------------- 1 | #ifndef SCT_CC_ 2 | #define SCT_CC_ 3 | 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | // Программа 19.11. Сильные компоненты (алгоритм Тарьяна) 9 | template 10 | class SCt { 11 | const Graph &G; 12 | stack S; 13 | int cnt, scnt; 14 | vector pre, low, id; 15 | 16 | void scR(int w) { 17 | int min = pre[w] = low[w] = cnt++; 18 | S.push(w); 19 | 20 | typename Graph::adjIterator A(G, w); 21 | for (int t = A.beg(); !A.end(); t = A.nxt()) { 22 | if (pre[t] == -1) scR(t); 23 | if (low[t] < min) min = low[t]; 24 | } 25 | 26 | if (min < low[w]) { 27 | low[w] = min; 28 | return; 29 | } 30 | 31 | int t; 32 | do { 33 | t = S.top(); 34 | S.pop(); 35 | id[t] = scnt; 36 | low[t] = G.V(); 37 | } while (t != w); 38 | scnt++; 39 | } 40 | 41 | public: 42 | SCt(const Graph &G) : G(G), cnt(0), scnt(0), pre(G.V(), -1), low(G.V(), -1), id(G.V()) { 43 | for (int v = 0; v < G.V(); v++) { 44 | if (pre[v] == -1) scR(v); 45 | } 46 | } 47 | 48 | int count() const { return scnt; } 49 | bool stronglyreachable(int v, int w) const { return id[v] == id[w]; } 50 | int ID(int v) const { return id[v]; } 51 | }; 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /cpp/first_half/SEARCH.cc: -------------------------------------------------------------------------------- 1 | #ifndef SEARCH_CC_ 2 | #define SEARCH_CC_ 3 | 4 | #include 5 | #include "Edge.cc" 6 | 7 | using namespace std; 8 | 9 | // Программа 18.2. Поиск на графе 10 | template 11 | class SEARCH { 12 | protected: 13 | const Graph &G; 14 | int cnt; 15 | vector ord; 16 | 17 | virtual void searchC(Edge) = 0; 18 | 19 | void search() { 20 | for (int v = 0; v < G.V(); v++) { 21 | if (ord[v] == -1) searchC(Edge(v, v)); 22 | } 23 | } 24 | 25 | public: 26 | SEARCH(const Graph &G) : G(G), cnt(0), ord(G.V(), -1) {} 27 | 28 | int operator [] (int v) const { return ord[v]; } 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /cpp/first_half/ST.cc: -------------------------------------------------------------------------------- 1 | #ifndef ST_CC_ 2 | #define ST_CC_ 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | // Программа 17.15. Символьная индексация имён вершин 9 | class ST { 10 | struct node { 11 | int v, d; 12 | node *l, *m, *r; 13 | node(int d) : v(-1), d(d), l(0), m(0), r(0) {} 14 | }; 15 | 16 | typedef node * link; 17 | 18 | int N, val; 19 | link head; 20 | 21 | link indexR(link h, const string &s, int w) { 22 | int i = s[w]; 23 | if (h == 0) h = new node(i); 24 | if (i == 0) { 25 | if (h->v == -1) h->v = N++; 26 | val = h->v; 27 | return h; 28 | } 29 | if (i < h->d) h->l = indexR(h->l, s, w); 30 | else if (i == h->d) h->m = indexR(h->m, s, w + 1); 31 | else if (i > h->d) h->r = indexR(h->r, s, w); 32 | return h; 33 | } 34 | 35 | void clearMemory(link h) { 36 | if (!h) return; 37 | if (h->l) clearMemory(h->l); 38 | if (h->m) clearMemory(h->m); 39 | if (h->r) clearMemory(h->r); 40 | delete h; 41 | } 42 | 43 | public: 44 | ST() : N(0), head(0) {} 45 | ~ST() { 46 | clearMemory(head); 47 | } 48 | 49 | int index(const string &key) { 50 | head = indexR(head, key, 0); 51 | return val; 52 | } 53 | }; 54 | 55 | #endif -------------------------------------------------------------------------------- /cpp/first_half/STLSparseMultiGRAPH.cc: -------------------------------------------------------------------------------- 1 | #ifndef STLSPARSEMULTIGRAPH_CC_ 2 | #define STLSPARSEMULTIGRAPH_CC_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "Edge.cc" 8 | 9 | using namespace std; 10 | 11 | // Упражнение 17.30 12 | 13 | class STLSparseMultiGRAPH { 14 | typedef list Links; 15 | 16 | public: 17 | class adjIterator; 18 | friend class adjIterator; 19 | 20 | STLSparseMultiGRAPH(int V, bool digraph = false) : 21 | Vcnt(V), Ecnt(0), digraph(digraph), adj(V) {} 22 | 23 | int V() const { return Vcnt; } 24 | int E() const { return Ecnt; } 25 | bool directed() const { return digraph; } 26 | 27 | void insert(Edge e) { 28 | int v = e.v, w = e.w; 29 | adj[v].push_back(w); 30 | if (!digraph && v != w) adj[w].push_back(v); 31 | ++Ecnt; 32 | } 33 | 34 | void remove(Edge e) { 35 | int v = e.v, w = e.w; 36 | Links::iterator p = find(adj[v].begin(), adj[v].end(), w); 37 | if (p != adj[v].end()) { 38 | adj[v].erase(p); 39 | 40 | if (!digraph && v != w) { 41 | p = find(adj[w].begin(), adj[w].end(), v); 42 | adj[w].erase(p); 43 | } 44 | 45 | --Ecnt; 46 | } 47 | } 48 | 49 | bool edge(int v, int w) const { 50 | return find(adj[v].begin(), adj[v].end(), w) != adj[v].end(); 51 | } 52 | 53 | // Упражнение 17.34 54 | void removeLoopsAndParallels() { 55 | Links around; 56 | int exist; 57 | 58 | for (int v = 0; v < Vcnt; ++v) { 59 | around.clear(); 60 | for (Links::const_iterator a = adj[v].begin(); a != adj[v].end(); ++a) { 61 | exist = -1; 62 | for (Links::const_iterator p = around.begin(); p != around.end(); ++p) { 63 | if (*p == *a) { 64 | exist = *p; 65 | break; 66 | } 67 | } 68 | 69 | if (exist == -1) around.push_back(*a); 70 | else remove(Edge(v, exist)); 71 | } 72 | 73 | remove(Edge(v, v)); 74 | } 75 | } 76 | 77 | private: 78 | int Vcnt, Ecnt; 79 | bool digraph; 80 | vector adj; 81 | }; 82 | 83 | class STLSparseMultiGRAPH::adjIterator { 84 | const STLSparseMultiGRAPH &G; 85 | int v; 86 | Links::const_iterator p; 87 | 88 | public: 89 | adjIterator(const STLSparseMultiGRAPH &G, int v) : G(G), v(v) {} 90 | 91 | int beg() { 92 | p = G.adj[v].begin(); 93 | return (p != G.adj[v].end()) ? *p : -1; 94 | } 95 | 96 | int nxt() { 97 | if (p != G.adj[v].end()) ++p; 98 | return (p != G.adj[v].end()) ? *p : -1; 99 | } 100 | 101 | bool end() { 102 | return p == G.adj[v].end(); 103 | } 104 | }; 105 | 106 | #endif 107 | -------------------------------------------------------------------------------- /cpp/first_half/SparseGRAPH.cc: -------------------------------------------------------------------------------- 1 | #ifndef SPARSEGRAPH_CC_ 2 | #define SPARSEGRAPH_CC_ 3 | 4 | #include 5 | #include "Edge.cc" 6 | 7 | using namespace std; 8 | 9 | // Упражнение 17.35 10 | class SparseGRAPH { 11 | struct node { 12 | int v; 13 | node *next; 14 | node(int x, node *t) : v(x), next(t) {} 15 | }; 16 | 17 | typedef node * link; 18 | 19 | public: 20 | class adjIterator; 21 | friend class adjIterator; 22 | 23 | SparseGRAPH(int V, bool digraph = false) : 24 | Vcnt(V), Ecnt(0), digraph(digraph), adj(V) 25 | { 26 | link t = 0; 27 | adj.assign(V, t); 28 | } 29 | 30 | // Упражнение 17.29 31 | SparseGRAPH(const SparseGRAPH &G) : 32 | Vcnt(G.V()), Ecnt(G.E()), digraph(G.directed()), adj(G.V()) 33 | { 34 | for (int i = 0; i < Vcnt; ++i) { 35 | link t = G.adj[i]; 36 | while (t) { 37 | adj[i] = new node(t->v, adj[i]); 38 | t = t->next; 39 | } 40 | } 41 | } 42 | 43 | ~SparseGRAPH() { 44 | for (vector::iterator p = adj.begin(); p != adj.end(); ++p) { 45 | link t = *p, prev; 46 | while (t) { 47 | prev = t; 48 | t = t->next; 49 | delete prev; 50 | } 51 | } 52 | } 53 | 54 | int V() const { return Vcnt; } 55 | int E() const { return Ecnt; } 56 | bool directed() const { return digraph; } 57 | 58 | void insert(Edge e) { 59 | int v = e.v, w = e.w; 60 | if (v == w || edge(v, w)) return; 61 | 62 | adj[v] = new node(w, adj[v]); 63 | if (!digraph) adj[w] = new node(v, adj[w]); 64 | ++Ecnt; 65 | } 66 | 67 | // Упражнение 17.28 68 | void remove(Edge e) { 69 | int v = e.v, w = e.w; 70 | link *t = &adj[v]; 71 | while (*t && (*t)->v != w) { 72 | t = &(*t)->next; 73 | } 74 | if (*t) { 75 | link nxt = (*t)->next; 76 | delete *t; 77 | *t = nxt; 78 | 79 | if (!digraph) { 80 | t = &adj[w]; 81 | while ((*t)->v != v) { 82 | t = &(*t)->next; 83 | } 84 | nxt = (*t)->next; 85 | delete *t; 86 | *t = nxt; 87 | } 88 | 89 | --Ecnt; 90 | } 91 | } 92 | bool edge(int v, int w) const { 93 | link t = adj[v]; 94 | while (t && t->v != w) t = t->next; 95 | return t; 96 | } 97 | 98 | // Упражнение 17.34 99 | void removeLoopsAndParallels() {} 100 | 101 | private: 102 | int Vcnt, Ecnt; 103 | bool digraph; 104 | vector adj; 105 | }; 106 | 107 | class SparseGRAPH::adjIterator { 108 | const SparseGRAPH &G; 109 | int v; 110 | link t; 111 | 112 | public: 113 | adjIterator(const SparseGRAPH &G, int v) : G(G), v(v), t(0) {} 114 | 115 | int beg() { 116 | t = G.adj[v]; 117 | return t ? t->v : -1; 118 | } 119 | 120 | int nxt() { 121 | if (t) t = t->next; 122 | return t ? t->v : -1; 123 | } 124 | 125 | bool end() { 126 | return t == 0; 127 | } 128 | }; 129 | 130 | #endif 131 | -------------------------------------------------------------------------------- /cpp/first_half/SparseMultiGRAPH.cc: -------------------------------------------------------------------------------- 1 | #ifndef SPARSEMULTIGRAPH_CC_ 2 | #define SPARSEMULTIGRAPH_CC_ 3 | 4 | #include 5 | #include "Edge.cc" 6 | 7 | using namespace std; 8 | 9 | // Программа 17.9 (расширенная). Реализация АДТ графа (списки смежных вершин) 10 | class SparseMultiGRAPH { 11 | int Vcnt, Ecnt; 12 | bool digraph; 13 | 14 | struct node { 15 | int v; 16 | node *next; 17 | node(int x, node *t) : v(x), next(t) {} 18 | }; 19 | typedef node * link; 20 | vector adj; 21 | 22 | public: 23 | SparseMultiGRAPH(int V, bool digraph = false) : 24 | Vcnt(V), Ecnt(0), digraph(digraph), adj(V) 25 | { 26 | link t = 0; 27 | adj.assign(V, t); 28 | } 29 | 30 | // Упражнение 17.29 31 | SparseMultiGRAPH(const SparseMultiGRAPH &G) : 32 | Vcnt(G.V()), Ecnt(G.E()), digraph(G.directed()), adj(G.V()) 33 | { 34 | for (int i = 0; i < Vcnt; ++i) { 35 | link t = G.adj[i]; 36 | while (t) { 37 | adj[i] = new node(t->v, adj[i]); 38 | t = t->next; 39 | } 40 | } 41 | } 42 | 43 | ~SparseMultiGRAPH() { 44 | for (int v = 0; v < Vcnt; ++v) { 45 | link t = adj[v], prev; 46 | while (t) { 47 | prev = t; 48 | t = t->next; 49 | delete prev; 50 | } 51 | } 52 | } 53 | 54 | int V() const { return Vcnt; } 55 | int E() const { return Ecnt; } 56 | bool directed() const { return digraph; } 57 | 58 | void insert(Edge e) { 59 | int v = e.v, w = e.w; 60 | adj[v] = new node(w, adj[v]); 61 | if (!digraph && v != w) adj[w] = new node(v, adj[w]); 62 | ++Ecnt; 63 | } 64 | 65 | // Упражнение 17.28 66 | void remove(Edge e) { 67 | int v = e.v, w = e.w; 68 | link *t = &adj[v]; 69 | while (*t && (*t)->v != w) { 70 | t = &(*t)->next; 71 | } 72 | if (*t) { 73 | link nxt = (*t)->next; 74 | delete *t; 75 | *t = nxt; 76 | 77 | if (!digraph && v != w) { 78 | t = &adj[w]; 79 | while ((*t)->v != v) { 80 | t = &(*t)->next; 81 | } 82 | nxt = (*t)->next; 83 | delete *t; 84 | *t = nxt; 85 | } 86 | 87 | --Ecnt; 88 | } 89 | } 90 | bool edge(int v, int w) const { 91 | link t = adj[v]; 92 | while (t && t->v != w) t = t->next; 93 | return t; 94 | } 95 | 96 | void insert() { 97 | link t = 0; 98 | adj.push_back(t); 99 | ++Vcnt; 100 | } 101 | 102 | void remove(int v) { 103 | link t = adj[v], backup; 104 | while (t) { 105 | backup = t; 106 | t = t->next; 107 | delete backup; 108 | --Ecnt; 109 | } 110 | adj.erase(adj.begin() + v); 111 | --Vcnt; 112 | 113 | link *pt; 114 | for (int i = 0; i < Vcnt; ++i) { 115 | pt = &adj[i]; 116 | while (*pt) { 117 | if ((*pt)->v == v) { 118 | backup = (*pt)->next; 119 | delete *pt; 120 | *pt = backup; 121 | if (digraph) --Ecnt; 122 | } else { 123 | if ((*pt)->v > v) --(*pt)->v; 124 | pt = &(*pt)->next; 125 | } 126 | } 127 | } 128 | } 129 | 130 | // Упражнение 17.34 131 | void removeLoopsAndParallels() { 132 | int *around = new int[Vcnt]; 133 | int a; 134 | bool exist; 135 | 136 | for (int v = 0; v < Vcnt; ++v) { 137 | a = 0; 138 | link t = adj[v]; 139 | while (t) { 140 | exist = false; 141 | for (int i = 0; i < a; ++i) { 142 | if (around[i] == t->v) { 143 | exist = true; 144 | break; 145 | } 146 | } 147 | 148 | if (exist) remove(Edge(v, t->v)); 149 | else around[a++] = t->v; 150 | 151 | t = t->next; 152 | } 153 | 154 | remove(Edge(v, v)); 155 | } 156 | 157 | delete [] around; 158 | } 159 | 160 | // Упражнение 17.43 161 | int degree(int v) { 162 | int n = 0; 163 | link t = adj[v]; 164 | while (t) { 165 | t = t->next; 166 | ++n; 167 | } 168 | return n; 169 | } 170 | 171 | // Упражнение 17.44 172 | int zeros() const { 173 | int n = 0; 174 | for (int v = 0; v < Vcnt; ++v) { 175 | if (!adj[v]) ++n; 176 | } 177 | return n; 178 | } 179 | 180 | class adjIterator; 181 | friend class adjIterator; 182 | }; 183 | 184 | // Программа 17.10. Итератор для представления графа в виде списка смежных вершин 185 | class SparseMultiGRAPH::adjIterator { 186 | const SparseMultiGRAPH &G; 187 | int v; 188 | link t; 189 | 190 | public: 191 | adjIterator(const SparseMultiGRAPH &G, int v) : G(G), v(v), t(0) {} 192 | 193 | int beg() { 194 | t = G.adj[v]; 195 | return t ? t->v : -1; 196 | } 197 | 198 | int nxt() { 199 | if (t) t = t->next; 200 | return t ? t->v : -1; 201 | } 202 | 203 | bool end() { 204 | return t == 0; 205 | } 206 | }; 207 | 208 | #endif 209 | -------------------------------------------------------------------------------- /cpp/first_half/StaticGRAPH.cc: -------------------------------------------------------------------------------- 1 | #ifndef STATICGRAPH_CC_ 2 | #define STATICGRAPH_CC_ 3 | 4 | #include 5 | #include "Edge.cc" 6 | 7 | using namespace std; 8 | 9 | // Упражнение 17.51 10 | 11 | class StaticGRAPH { 12 | public: 13 | StaticGRAPH(const vector &); 14 | ~StaticGRAPH(); 15 | 16 | int V() const; 17 | int E() const; 18 | bool directed() const; 19 | 20 | void insert(const Edge &); 21 | void remove(const Edge &); 22 | bool edge(int, int) const; 23 | 24 | void insert(); 25 | void remove(int); 26 | 27 | void removeLoopsAndParallels(); 28 | 29 | class adjIterator { 30 | public: 31 | adjIterator(const StaticGRAPH &, int); 32 | int beg(); 33 | int nxt(); 34 | bool end(); 35 | }; 36 | }; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /cpp/first_half/StaticMultiGRAPH.cc: -------------------------------------------------------------------------------- 1 | #ifndef STATICMULTIGRAPH_CC_ 2 | #define STATICMULTIGRAPH_CC_ 3 | 4 | #include 5 | #include 6 | #include "Edge.cc" 7 | #include "EdgeSorter.h" 8 | 9 | using namespace std; 10 | 11 | // Упражнение 17.52 12 | 13 | class StaticMultiGRAPH { 14 | struct node { 15 | // int cnt; // wtf?? 16 | vector edges; 17 | }; 18 | 19 | public: 20 | class adjIterator; 21 | friend class adjIterator; 22 | 23 | StaticMultiGRAPH(int V, bool digraph = false) : Ecnt(0), digraph(digraph), adj(V) {} 24 | 25 | StaticMultiGRAPH(const vector &edges, bool digraph = false) : 26 | Ecnt(0), digraph(digraph) 27 | { 28 | const vector &sortedEdges = sortEdges(edges); 29 | for (vector::const_iterator p = sortedEdges.begin(); p != sortedEdges.end(); ++p) { 30 | insert(*p); 31 | } 32 | } 33 | 34 | int V() const { return (int)adj.size(); } 35 | int E() const { return Ecnt; } 36 | bool directed() const { return digraph; } 37 | 38 | void insert(const Edge &e) { 39 | simpleInsert(e.v, e.w); 40 | if (!digraph && e.v != e.w) simpleInsert(e.w, e.v); 41 | ++Ecnt; 42 | } 43 | 44 | void remove(const Edge &e) { 45 | if (!edge(e.v, e.w)) return; 46 | simpleRemove(e.v, e.w); 47 | if (!digraph && e.v != e.w) simpleRemove(e.w, e.v); 48 | --Ecnt; 49 | } 50 | 51 | bool edge(int v, int w) const { 52 | return find(adj[v].edges.begin(), adj[v].edges.end(), w) != adj[v].edges.end(); 53 | } 54 | 55 | void insert() { 56 | adj.push_back(node()); 57 | } 58 | 59 | void remove(int v) { 60 | Ecnt -= adj[v].edges.size(); 61 | adj.erase(adj.begin() + v); 62 | for (vector::iterator p = adj.begin(); p != adj.end(); ++p) { 63 | for (vector::iterator i = p->edges.begin(); i != p->edges.end(); ) { 64 | if (*i == v) { 65 | p->edges.erase(i); 66 | } else { 67 | if (*i > v) --(*i); 68 | ++i; 69 | } 70 | } 71 | } 72 | } 73 | 74 | // Упражнение 17.53 75 | void removeLoopsAndParallels() { 76 | vector around; 77 | for (int v = 0; v < V(); ++v) { 78 | around.clear(); 79 | for (vector::iterator i = adj[v].edges.begin(); i != adj[v].edges.end(); ) { 80 | if (*i == v) { 81 | adj[v].edges.erase(i); 82 | --Ecnt; 83 | } else if (find(around.begin(), around.end(), *i) != around.end()) { 84 | adj[v].edges.erase(i); 85 | if (!digraph) simpleRemove(*i, v); 86 | --Ecnt; 87 | } else { 88 | around.push_back(*i); 89 | ++i; 90 | } 91 | } 92 | } 93 | } 94 | 95 | private: 96 | void simpleInsert(int v, int w) { 97 | if (v >= (int)adj.size()) adj.push_back(node()); 98 | adj[v].edges.push_back(w); 99 | } 100 | 101 | void simpleRemove(int v, int w) { 102 | vector::iterator p = find(adj[v].edges.begin(), adj[v].edges.end(), w); 103 | if (p != adj[v].edges.end()) adj[v].edges.erase(p); 104 | } 105 | 106 | private: 107 | int Ecnt; 108 | bool digraph; 109 | vector adj; 110 | }; 111 | 112 | class StaticMultiGRAPH::adjIterator { 113 | public: 114 | adjIterator(const StaticMultiGRAPH &G, int v) : 115 | G(G), v(v), i(G.adj[v].edges.begin()) {} 116 | 117 | int beg() { 118 | i = G.adj[v].edges.begin(); 119 | return (end()) ? -1 : *i; 120 | } 121 | 122 | int nxt() { 123 | return *(++i); 124 | } 125 | 126 | bool end() { 127 | return i == G.adj[v].edges.end(); 128 | } 129 | 130 | private: 131 | const StaticMultiGRAPH &G; 132 | int v; 133 | vector::const_iterator i; 134 | }; 135 | 136 | #endif 137 | -------------------------------------------------------------------------------- /cpp/first_half/TC.cc: -------------------------------------------------------------------------------- 1 | #ifndef TC_CC_ 2 | #define TC_CC_ 3 | 4 | #include "Edge.cc" 5 | 6 | // Программа 19.3. Алгоритм Уоршала 7 | template 8 | class TC { 9 | tcGraph T; 10 | 11 | public: 12 | TC(const Graph &G) : T(G) { 13 | for (int s = 0; s < T.V(); s++) T.insert(Edge(s, s)); 14 | for (int i = 0; i < T.V(); i++) { 15 | for (int s = 0; s < T.V(); s++) { 16 | if (!T.edge(s, i)) continue; 17 | for (int t = 0; t < T.V(); t++) { 18 | if (T.edge(t, i)) T.insert(Edge(s, t)); 19 | } 20 | } 21 | } 22 | } 23 | 24 | bool reachable(int s, int t) const { 25 | return T.edge(s, t); 26 | } 27 | }; 28 | 29 | #endif -------------------------------------------------------------------------------- /cpp/first_half/TCsc.cc: -------------------------------------------------------------------------------- 1 | #ifndef TCSC_CC_ 2 | #define TCSC_CC_ 3 | 4 | #include "DenseGRAPH.cc" 5 | #include "dagTC.cc" 6 | // #include "SCc.cc" 7 | // #include "SCt.cc" 8 | #include "SCg.cc" 9 | 10 | // Программа 19.13. Транзитивное замыкание на основе сильных компонент 11 | template 12 | class TCsc { 13 | const Graph &G; 14 | DenseGRAPH *K; 15 | dagTC *Ktc; 16 | SCg *Gsc; 17 | 18 | public: 19 | TCsc(const Graph &G) : G(G) { 20 | Gsc = new SCg(G); 21 | K = new DenseGRAPH(Gsc->count, true); 22 | for (int v = 0; v < G.V(); v++) { 23 | typename Graph::adjIterator A(G, v); 24 | for (int t = A.beg(); !A.end(); t = A.nxt()) { 25 | K->insert(Edge(Gsc->ID(v), Gsc->ID(t))); 26 | } 27 | } 28 | Ktc = new dagTC(*K); 29 | } 30 | 31 | ~TCsc() { 32 | delete K; 33 | delete Ktc; 34 | delete Gsc; 35 | } 36 | 37 | bool reachable(int v, int w) const { 38 | return Ktc->reachable(Gsc->ID(v), Gsc->ID(w)); 39 | } 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /cpp/first_half/UndirBitDenseGRAPH.cc: -------------------------------------------------------------------------------- 1 | #ifndef UNDIRBITDENSEGRAPH_H_ 2 | #define UNDIRBITDENSEGRAPH_H_ 3 | 4 | #include "Edge.cc" 5 | 6 | using namespace std; 7 | 8 | // Упражнение 17.23 9 | 10 | class UndirBitDenseGRAPH { 11 | public: 12 | class adjIterator; 13 | friend class adjIterator; 14 | 15 | UndirBitDenseGRAPH(int V) : Vcnt(V), Ecnt(0) { 16 | int N = countUp(1); 17 | allocMem(N); 18 | } 19 | 20 | UndirBitDenseGRAPH(const UndirBitDenseGRAPH &G) : Vcnt(G.V()), Ecnt(G.E()) { 21 | int N = countUp(1); 22 | int allocated = N / bitsize(); 23 | if (N % bitsize() > 0) ++allocated; 24 | adj = new int[allocated]; 25 | for (int i = 0; i < allocated; i++) adj[i] = G.adj[i]; 26 | } 27 | 28 | ~UndirBitDenseGRAPH() { 29 | delete [] adj; 30 | } 31 | 32 | int V() const { return Vcnt; } 33 | int E() const { return Ecnt; } 34 | bool directed() const { return false; } 35 | 36 | void insert(Edge e) { 37 | if (!edge(e.v, e.w)) ++Ecnt; 38 | setEdge(e.v, e.w, 1); 39 | } 40 | 41 | void remove(Edge e) { 42 | if (edge(e.v, e.w)) --Ecnt; 43 | setEdge(e.v, e.w, 0); 44 | } 45 | 46 | bool edge(int v, int w) const { 47 | int i, seek; 48 | setupCarrete(i, seek, v, w); 49 | return adj[i] & (1 << seek); 50 | } 51 | 52 | void insert() { 53 | int newElementsNum = countUp(1, Vcnt + 1); 54 | int *fatArj = new int[newElementsNum]; 55 | for (int k = 0; k < newElementsNum; k++) { 56 | fatArj[k] = 0; 57 | } 58 | 59 | int i = -1; 60 | for (int v = 0; v < Vcnt; ++v) { 61 | for (int w = v; w < Vcnt + 1; ++w) { 62 | ++i; 63 | if (w == Vcnt) continue; 64 | fatArj[i] = edge(v, w); 65 | } 66 | } 67 | 68 | delete [] adj; 69 | allocMem(newElementsNum); 70 | ++Vcnt; 71 | 72 | fillFromFat(fatArj); 73 | delete [] fatArj; 74 | } 75 | 76 | void remove(int v) { 77 | for (int i = 0; i < Vcnt; ++i) { 78 | if (edge(v, i)) --Ecnt; 79 | } 80 | 81 | int newElementsNum = countUp(1, Vcnt - 1); 82 | int *fatArj = new int[newElementsNum]; 83 | int i = 0; 84 | for (int u = 0; u < Vcnt; ++u) { 85 | if (u == v) continue; 86 | for (int w = u; w < Vcnt; ++w) { 87 | if (v >= u && (w - u) == (u - v)) continue; 88 | fatArj[i++] = edge(u, w); 89 | } 90 | } 91 | 92 | delete [] adj; 93 | allocMem(newElementsNum); 94 | --Vcnt; 95 | 96 | fillFromFat(fatArj); 97 | delete [] fatArj; 98 | } 99 | 100 | // Упражнение 17.34 101 | void removeLoopsAndParallels() { 102 | for (int v = 0; v < Vcnt; ++v) remove(Edge(v, v)); 103 | } 104 | 105 | private: 106 | void setEdge(int v, int w, int value) { 107 | int i, seek; 108 | setupCarrete(i, seek, v, w); 109 | if (value == 0) { 110 | adj[i] ^= (1 << seek); 111 | } else { 112 | adj[i] |= (1 << seek); 113 | } 114 | } 115 | 116 | int bitsize() const { 117 | return (int)sizeof(int); 118 | } 119 | 120 | void allocMem(int N) { 121 | int allocated = N / bitsize(); 122 | if (N % bitsize() > 0) ++allocated; 123 | adj = new int[allocated]; 124 | for (int i = 0; i < allocated; i++) adj[i] = 0; 125 | } 126 | 127 | // arithmetic progression 128 | int countUp(int initialValue, int V = -1) const { 129 | if (V == -1) V = Vcnt; 130 | return (int)((V - initialValue + 1) * (initialValue + V) * 0.5); 131 | } 132 | 133 | void setupCarrete(int &i, int &seek, int v, int w) const { 134 | int _v, _w; 135 | if (v < w) { 136 | _v = v; 137 | _w = w; 138 | } else { 139 | _v = w; 140 | _w = v; 141 | } 142 | 143 | int before = (_v > 0) ? countUp(Vcnt - _v + 1) : 0; 144 | int currElement = before + _w - _v; 145 | 146 | i = currElement / bitsize(); 147 | seek = bitsize() - currElement % bitsize() - 1; 148 | } 149 | 150 | void fillFromFat(int *fatArj) { 151 | int i = 0; 152 | for (int v = 0; v < Vcnt; ++v) { 153 | for (int w = v; w < Vcnt; ++w) { 154 | setEdge(v, w, fatArj[i++]); 155 | } 156 | } 157 | } 158 | 159 | private: 160 | int Vcnt, Ecnt; 161 | int *adj; 162 | }; 163 | 164 | class UndirBitDenseGRAPH::adjIterator { 165 | public: 166 | adjIterator(const UndirBitDenseGRAPH &G, int v) : G(G), v(v), i(-1) {} 167 | 168 | int beg() { 169 | i = -1; 170 | return nxt(); 171 | } 172 | 173 | int nxt() { 174 | for (i++; i < G.V(); i++) { 175 | if (G.edge(v, i)) return i; 176 | } 177 | return -1; 178 | } 179 | 180 | bool end() { 181 | return i >= G.V(); 182 | } 183 | 184 | private: 185 | const UndirBitDenseGRAPH &G; 186 | int v, i; 187 | }; 188 | 189 | #endif 190 | -------------------------------------------------------------------------------- /cpp/first_half/UndirDenseGRAPH.cc: -------------------------------------------------------------------------------- 1 | #ifndef UNDIRDENSEGRAPH_H_ 2 | #define UNDIRDENSEGRAPH_H_ 3 | 4 | #include 5 | #include "Edge.cc" 6 | 7 | using namespace std; 8 | 9 | // Упражнение 17.22 10 | 11 | class UndirDenseGRAPH { 12 | public: 13 | class adjIterator; 14 | friend class adjIterator; 15 | 16 | UndirDenseGRAPH(int V) : Vcnt(V), Ecnt(0), adj(V) { 17 | for (int i = 0; i < V; i++) adj[i].assign(V - i, false); 18 | } 19 | 20 | int V() const { return Vcnt; } 21 | int E() const { return Ecnt; } 22 | bool directed() const { return false; } 23 | 24 | void insert(Edge e) { 25 | if (!edge(e.v, e.w)) ++Ecnt; 26 | setEdge(e, true); 27 | } 28 | 29 | void remove(Edge e) { 30 | if (edge(e.v, e.w)) --Ecnt; 31 | setEdge(e, false); 32 | } 33 | 34 | bool edge(int v, int w) const { 35 | int _v, _w; 36 | if (v < w) { 37 | _v = v; 38 | _w = w; 39 | } else { 40 | _v = w; 41 | _w = v; 42 | } 43 | return adj[_v][_w - _v]; 44 | } 45 | 46 | void insert() { 47 | for (vector< vector >::iterator p = adj.begin(); p != adj.end(); ++p) { 48 | p->push_back(false); 49 | } 50 | adj.push_back(vector(1, false)); 51 | ++Vcnt; 52 | } 53 | 54 | void remove(int v) { 55 | for (int i = 0; i < Vcnt; ++i) { 56 | if (edge(v, i)) --Ecnt; 57 | } 58 | adj.erase(adj.begin() + v); 59 | 60 | for (int i = 0; i < v; ++i) { 61 | vector::iterator p = adj[i].begin() + (v - i); 62 | adj[i].erase(p); 63 | } 64 | --Vcnt; 65 | } 66 | 67 | // Упражнение 17.34 68 | void removeLoopsAndParallels() { 69 | for (int v = 0; v < Vcnt; ++v) { 70 | if (adj[v][0]) --Ecnt; 71 | adj[v][0] = false; 72 | } 73 | } 74 | 75 | private: 76 | void setEdge(const Edge &e, bool value) { 77 | int v, w; 78 | if (e.v < e.w) { 79 | v = e.v; 80 | w = e.w; 81 | } else { 82 | v = e.w; 83 | w = e.v; 84 | } 85 | adj[v][w - v] = value; 86 | } 87 | 88 | private: 89 | int Vcnt, Ecnt; 90 | vector< vector > adj; 91 | 92 | }; 93 | 94 | class UndirDenseGRAPH::adjIterator { 95 | public: 96 | adjIterator(const UndirDenseGRAPH &G, int v) : G(G), v(v), i(-1) {} 97 | 98 | int beg() { 99 | i = -1; 100 | return nxt(); 101 | } 102 | 103 | int nxt() { 104 | for (i++; i < G.V(); i++) { 105 | if (G.edge(v, i)) return i; 106 | } 107 | return -1; 108 | } 109 | 110 | bool end() { 111 | return i >= G.V(); 112 | } 113 | 114 | private: 115 | const UndirDenseGRAPH &G; 116 | int v, i; 117 | }; 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /cpp/first_half/cDFS.cc: -------------------------------------------------------------------------------- 1 | #ifndef CDFS_CC_ 2 | #define CDFS_CC_ 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | // Программа 18.1. Поиск в глубину связной компоненты 9 | template 10 | class cDFS { 11 | const Graph &G; 12 | int cnt; 13 | vector ord; 14 | 15 | void searchC(int v) { 16 | ord[v] = cnt++; 17 | typename Graph::adjIterator A(G, v); 18 | for (int t = A.beg(); !A.end(); t = A.nxt()) { 19 | if (ord[t] == -1) searchC(t); 20 | } 21 | } 22 | 23 | public: 24 | cDFS(const Graph &G, int v = 0) : G(G), ord(0), ord(G.V(), -1) { 25 | searchC(v); 26 | } 27 | 28 | int count() const { return cnt; } 29 | int operator [] (int v) const { return ord[v]; } 30 | }; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /cpp/first_half/clients.cc: -------------------------------------------------------------------------------- 1 | #ifndef BASIC_CC_ 2 | #define BASIC_CC_ 3 | 4 | #include 5 | #include 6 | #include "Edge.cc" 7 | #include "DEGREE.cc" 8 | 9 | using namespace std; 10 | 11 | // Программа 17.2. Пример клиентской функции обработки графов 12 | template 13 | vector edges(const Graph &G) { 14 | int E = 0; 15 | vector a(G.E()); 16 | for (int v = 0; v < G.V(); v++) { 17 | typename Graph::adjIterator A(G, v); 18 | for (int w = A.beg(); !A.end(); w = A.nxt()) { 19 | if (G.directed() || v <= w) a[E++] = Edge(v, w); 20 | } 21 | } 22 | return a; 23 | } 24 | 25 | // Упражнение 17.13 26 | template 27 | void addEdgesFromVectorToGraph(Graph &G, const vector &vec) { 28 | for (vector::const_iterator p = vec.begin(); p != vec.end(); ++p) { 29 | G.insert(*p); 30 | } 31 | } 32 | 33 | // Упражнение 17.26 34 | template 35 | bool hasSeqClique(const Graph &G, int beg, int end) { 36 | if (beg == end) return true; 37 | return G.edge(beg, end) && hasSeqClique(G, beg + 1, end); 38 | } 39 | template 40 | void findMaxSeqClique(const Graph &G) { 41 | int beg = -1, end = -1; 42 | int v = 0, w; 43 | while (v < G.V() - 1) { 44 | w = 0; 45 | while (v + w + 1 < G.V() && hasSeqClique(G, v, v + w + 1)) ++w; 46 | if (w > 2 && w > end - beg) { 47 | beg = v; 48 | end = v + w; 49 | v += w; 50 | } else { 51 | ++v; 52 | } 53 | } 54 | 55 | if (beg == -1 && end == -1) { 56 | cout << "No sequence cluque found" << endl; 57 | } else { 58 | cout << "Max sequence clique is: " << beg << "-" << end << endl; 59 | } 60 | } 61 | 62 | // Упражнение 17.36 (обновлённое) 63 | template 64 | Graph removeZerosLoopsParallels(const Graph &G) { 65 | int unzeros = 0; 66 | DEGREE dg(G); 67 | for (int v = 0; v < G.V(); v++) { 68 | if (dg[v] > 0) ++unzeros; 69 | } 70 | 71 | Graph newG(unzeros); 72 | addEdgesFromVectorToGraph(newG, edges(G)); 73 | newG.removeLoopsAndParallels(); 74 | return newG; 75 | } 76 | 77 | // Упражнение 17.44 78 | template 79 | int zeros(const Graph &G) { 80 | vector rel(G.V(), false); 81 | vector vec = edges(G); 82 | for (vector::iterator p = vec.begin(); p != vec.end(); ++p) { 83 | rel[p->v] = true; 84 | rel[p->w] = true; 85 | } 86 | 87 | int n = 0; 88 | for (int v = 0; v < G.V(); ++v) { 89 | if (!rel[v]) ++n; 90 | } 91 | return n; 92 | } 93 | 94 | // Программа 19.1. Обращение орграфа 95 | template 96 | void reverse(const inGraph &G, outGraph &R) { 97 | for (int v = 0; v < G.V(); v++) { 98 | typename inGraph::adjIterator A(G, v); 99 | for (int w = A.beg(); !A.end(); w = A.nxt()) { 100 | R.insert(Edge(w, v)); 101 | } 102 | } 103 | } 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /cpp/first_half/dagTC.cc: -------------------------------------------------------------------------------- 1 | #ifndef DAGTC_CC_ 2 | #define DAGTC_CC_ 3 | 4 | #include 5 | #include "Edge.cc" 6 | using namespace std; 7 | 8 | // Программа 19.9. Транзитивное замыкание графа DAG 9 | template 10 | class dagTC { 11 | const Dag &D; 12 | tcDag T; 13 | int cnt; 14 | vector pre; 15 | 16 | void tcR(int w) { 17 | pre[w] = cnt++; 18 | typename Dag::adjIterator A(D, w); 19 | for (int t = A.beg(); !A.end(); t = A.nxt()) { 20 | T.insert(Edge(w, t)); 21 | if (pre[t] > pre[w]) continue; 22 | if (pre[t] == -1) tcR(t); 23 | for (int i = 0; i < T.V(); i++) { 24 | if (T.edge(t, i)) T.insert(Edge(w, i)); 25 | } 26 | } 27 | } 28 | 29 | public: 30 | dagTC(const Dag &D) : D(D), T(D.V(), true), cnt(0), pre(D.V(), -1) { 31 | for (int v = 0; v < D.V(); v++) { 32 | if (pre[v] == -1) tcR(v); 33 | } 34 | } 35 | 36 | bool reahable(int v, int w) const { return T.edge(v, w); } 37 | }; 38 | 39 | #endif -------------------------------------------------------------------------------- /cpp/first_half/dagTSq.cc: -------------------------------------------------------------------------------- 1 | #ifndef DAGTSQ_CC_ 2 | #define DAGTSQ_CC_ 3 | 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | // Программа 19.8. Топологическая сортировка основанная на очереди истоков 9 | template 10 | class dagTSq { 11 | const Dag &D; 12 | vector in, ts, tsI; 13 | 14 | public: 15 | dagTSq(const Dag &D) : D(D), in(D.V(), 0), ts(D.V(), -1), tsI(D.V(), -1) { 16 | queue Q; 17 | for (int v = 0; v < D.V(); v++) { 18 | typename Dag::adjIterator A(D, v); 19 | for (int t = A.beg(); !A.end(); t = A.nxt()) in[t]++; 20 | } 21 | 22 | for (int v = 0; v < D.V(); v++) { 23 | if (in[v] == 0) Q.push(v); 24 | } 25 | 26 | for (int j = 0; !Q.empty(); j++) { 27 | ts[j] = Q.front(); 28 | Q.pop(); 29 | tsI[ts[j]] = j; 30 | typename Dag::adjIterator A(D, ts[j]); 31 | for (int t = A.beg(); !A.end(); t = A.nxt()) { 32 | if (--in[t] == 0) Q.push(t); 33 | } 34 | } 35 | } 36 | 37 | int operator [] (int v) const { return ts[v]; } 38 | int relabel(int v) const { return tsI[v]; } 39 | }; 40 | 41 | #endif -------------------------------------------------------------------------------- /cpp/first_half/dagTSr.cc: -------------------------------------------------------------------------------- 1 | #ifndef DAGTSR_CC_ 2 | #define DAGTSR_CC_ 3 | 4 | #include 5 | using namespace std; 6 | 7 | // Программа 19.7. Топологическая сортировка 8 | template 9 | class dagTSr { 10 | const Dag &D; 11 | int cnt, tcnt; 12 | vector pre, post, postI; 13 | 14 | void tsR(int v) { 15 | pre[v] = cnt++; 16 | 17 | for (int w = 0; w < D.V(); w++) { 18 | if (D.edge(w, v) && pre[w] == -1) tsR(w); 19 | } 20 | 21 | post[v] = tcnt; 22 | postI[tcnt++] = v; 23 | } 24 | 25 | public: 26 | dagTSr(const Dag &D) : D(D), cnt(0), tcnt(0), 27 | pre(D.V(), -1), post(D.V(), -1), postI(D.V(), -1) 28 | { 29 | for (int v = 0; v < D.V(); v++) { 30 | if (pre[v] == -1) tsR(v); 31 | } 32 | } 33 | 34 | int operator [] (int v) const { return postI[v]; } 35 | int relabel(int v) const { return post[v]; } 36 | }; 37 | 38 | #endif -------------------------------------------------------------------------------- /cpp/first_half/dagTSs.cc: -------------------------------------------------------------------------------- 1 | #ifndef DAGTSS_CC_ 2 | #define DAGTSS_CC_ 3 | 4 | #include 5 | using namespace std; 6 | 7 | // Программа 19.6. Обратная топологическая сортировка 8 | template 9 | class dagTSs { 10 | const Dag &D; 11 | int cnt, tcnt; 12 | vector pre, post, postI; 13 | 14 | void tsR(int v) { 15 | pre[v] = cnt++; 16 | typename Dag::adjIterator A(D, v); 17 | for (int t = A.beg(); !A.end(); t = A.nxt()) { 18 | if (pre[v] == -1) tsR(t); 19 | } 20 | post[v] = tcnt; 21 | postI[tcnt++] = v; 22 | } 23 | 24 | public: 25 | dagTSs(const Dag &D) : D(D), cnt(0), tcnt(0), 26 | pre(D.V(), -1), post(D.V(), -1), postI(D.V(), -1) 27 | { 28 | for (int v = 0; v < D.V(); v++) { 29 | if (pre[v] == -1) tsR(v); 30 | } 31 | } 32 | 33 | int operator [] (int v) const { return postI[v]; } 34 | int relabel(int v) const { return post[v]; } 35 | }; 36 | 37 | #endif -------------------------------------------------------------------------------- /cpp/first_half/ePATH.cc: -------------------------------------------------------------------------------- 1 | #ifndef EPATH_CC_ 2 | #define EPATH_CC_ 3 | 4 | #include 5 | #include 6 | #include "DEGREE.cc" 7 | #include "Edge.cc" 8 | 9 | using namespace std; 10 | 11 | // Программа 17.18. Существование эйлерова цикла 12 | template 13 | class ePATH { 14 | Graph G; 15 | int v, w; 16 | bool found; 17 | stack S; 18 | 19 | int tour(int v); 20 | 21 | public: 22 | ePATH(const Graph &G, int v, int w) : G(G), v(v), w(w) { 23 | DEGREE deg(G); 24 | int t = deg[v] + deg[w]; 25 | if (t % 2 != 0) { 26 | found = false; 27 | return; 28 | } 29 | 30 | for (t = 0; t < G.V(); t++) { 31 | if (t != v && t != w && deg[t] % 2 != 0) { 32 | found = false; 33 | return; 34 | } 35 | } 36 | 37 | found = true; 38 | } 39 | 40 | bool exist() const { 41 | return found; 42 | } 43 | 44 | void show(); 45 | }; 46 | 47 | // Программа 17.19 (обновлённая). Поиск эйлерова пути с линейным временем выполнения 48 | template 49 | int ePATH::tour(int v) { 50 | while (true) { 51 | typename Graph::adjIterator A(G, v); 52 | int t = A.beg(); 53 | if (A.end()) break; 54 | 55 | S.push(v); 56 | G.remove(Edge(v, t)); 57 | v = t; 58 | } 59 | return v; 60 | } 61 | template 62 | void ePATH::show() { 63 | if (!found) return; 64 | cout << v; 65 | while (tour(v) == v && !S.empty()) { 66 | v = S.top(); 67 | S.pop(); 68 | cout << "-" << v; 69 | } 70 | cout << endl; 71 | } 72 | 73 | #endif -------------------------------------------------------------------------------- /cpp/first_half/gPATH.cc: -------------------------------------------------------------------------------- 1 | #ifndef GPATH_CC_ 2 | #define GPATH_CC_ 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | // Программа 17.17. Гамильтонов путь 9 | template 10 | class gPATH { 11 | const Graph &G; 12 | vector visited; 13 | bool found; 14 | 15 | bool searchR(int v, int w, int d) { 16 | if (v == w) return d == 0; 17 | visited[v] = true; 18 | typename Graph::adjIterator A(G, v); 19 | for (int t = A.beg(); !A.end(); t = A.nxt()) { 20 | if (!visited[t] && searchR(t, w, d - 1)) return true; 21 | } 22 | visited[v] = false; 23 | return false; 24 | } 25 | 26 | public: 27 | gPATH(const Graph &G, int v, int w) : G(G), visited(G.V(), false) { 28 | found = searchR(v, w, G.V() - 1); 29 | } 30 | 31 | bool exist() const { 32 | return found; 33 | } 34 | }; 35 | 36 | #endif -------------------------------------------------------------------------------- /cpp/first_half/inputs.txt: -------------------------------------------------------------------------------- 1 | 0 3 2 3 0 1 1 3 0 2 2 | 3 | 4 | 0 3 2 3 0 1 1 3 0 2 0 0 1 1 3 3 2 3 2 3 0 0 0 0 5 | 6 | 7 | 0 1 0 2 0 3 1 3 1 4 2 5 2 9 3 6 4 7 4 8 5 8 5 9 6 7 6 9 7 8 8 | 9 | 10 | 4 1 7 9 6 2 7 3 5 0 0 2 0 8 1 6 3 9 6 3 2 8 1 5 9 8 4 5 4 7 11 | 12 | 13 | 14 | | 0 1 2 3 4 5 6 7 8 9 10 15 | -------------------------------------- 16 | 0 | 0 1 1 0 0 1 0 0 0 0 0 17 | 1 | 1 0 1 1 1 0 0 0 0 0 0 18 | 2 | 1 1 0 1 1 0 0 0 0 0 0 19 | 3 | 0 1 1 0 1 0 0 1 0 0 0 20 | 4 | 0 1 1 1 0 1 1 0 0 0 0 21 | 5 | 1 0 0 0 1 0 0 0 1 0 0 22 | 6 | 0 0 0 0 1 0 0 1 1 1 1 23 | 7 | 0 0 0 1 0 0 1 0 1 1 1 24 | 8 | 0 0 0 0 0 1 1 1 0 1 1 25 | 9 | 0 0 0 0 0 0 1 1 1 0 1 26 | 10 | 0 0 0 0 0 0 1 1 1 1 0 27 | 28 | 0 1 0 2 0 5 1 2 1 3 1 4 2 3 2 4 3 4 3 7 4 5 4 6 5 8 6 7 6 8 6 9 6 10 7 8 7 9 7 10 8 9 8 10 9 10 29 | 30 | 31 | 0 1 0 2 1 2 1 3 1 4 2 3 2 4 3 4 32 | 33 | 34 | 3 7 1 4 7 8 0 5 5 2 3 8 2 9 0 6 4 9 2 6 6 4 35 | 36 | 37 | 0 1 0 2 0 5 0 6 1 2 2 3 2 4 3 4 4 5 4 6 38 | 39 | 40 | 0 1 0 3 1 2 1 4 1 5 2 5 3 4 3 6 3 9 4 5 4 7 5 8 6 7 7 8 7 9 41 | 42 | 43 | 0 2 0 5 0 7 1 7 2 6 3 4 3 5 4 5 4 6 4 7 44 | 45 | 46 | di: 47 | 48 | 0 1 0 5 0 6 2 0 2 3 3 2 3 5 4 3 4 2 4 11 5 4 6 4 6 9 7 6 7 8 8 7 8 9 9 10 9 11 10 12 11 12 12 9 49 | 50 | 51 | 2 4 4 5 5 2 3 2 4 1 5 0 52 | 53 | 54 | 0 1 0 2 0 3 1 2 2 4 3 4 55 | 56 | -------------------------------------------------------------------------------- /cpp/first_half/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "process_mem_usage.h" 4 | 5 | #include "DenseGRAPH.cc" 6 | #include "UndirDenseGRAPH.cc" 7 | #include "UndirBitDenseGRAPH.cc" 8 | #include "DenseMultiGRAPH.cc" 9 | #include "SparseGRAPH.cc" 10 | #include "EdgeOptimalSparseGRAPH.cc" 11 | #include "SparseMultiGRAPH.cc" 12 | #include "STLSparseMultiGRAPH.cc" 13 | #include "StaticMultiGRAPH.cc" 14 | 15 | #include "IO.cc" 16 | 17 | #include "sPATH.cc" 18 | #include "gPATH.cc" 19 | #include "ePATH.cc" 20 | 21 | #include "DFS.cc" 22 | #include "InfoDFS.cc" 23 | #include "CC.cc" 24 | #include "EULER.cc" 25 | #include "BI.cc" 26 | #include "BFS.cc" 27 | #include "PFS.cc" 28 | 29 | #include "TC.cc" 30 | #include "tc.cc" 31 | #include "TCsc.cc" 32 | 33 | #include "SCc.cc" 34 | #include "SCt.cc" 35 | #include "SCg.cc" 36 | 37 | // typedef DenseGRAPH Graph; 38 | // typedef UndirDenseGRAPH Graph; 39 | // typedef UndirBitDenseGRAPH Graph; 40 | // typedef DenseMultiGRAPH Graph; 41 | // typedef SparseGRAPH Graph; 42 | // typedef EdgeOptimalSparseGRAPH Graph; 43 | typedef SparseMultiGRAPH Graph; 44 | // typedef STLSparseMultiGRAPH Graph; 45 | // typedef StaticMultiGRAPH Graph; 46 | 47 | // typedef DFS DFST; 48 | typedef InfoDFS DFST; 49 | // typedef EULER DFST; 50 | // typedef BI DFST; 51 | 52 | typedef SCg SC; 53 | 54 | void graphInfo(const Graph &G) { 55 | IO::show(G); 56 | IO::showEdges(G); 57 | IO::showAdj(G); 58 | } 59 | 60 | void removeAllEdges(Graph &G) { 61 | vector vec = edges(G); 62 | for (vector::iterator p = vec.begin(); p != vec.end(); ++p) { 63 | G.remove(*p); 64 | } 65 | } 66 | 67 | // Упражнение 17.65, 17.66 68 | void measure(char *argv[]) { 69 | Graph G(atoi(argv[1]), true); 70 | IO::scanEZ(G); 71 | 72 | timeval tBegin, tEnd; 73 | gettimeofday(&tBegin, NULL); 74 | 75 | // BODY --> 76 | 77 | // IO::randG(G, 2 * G.V()); 78 | DFST s(G); 79 | // cout << "OK = " << s.bipartite() << endl; 80 | 81 | // <-- BODY 82 | 83 | gettimeofday(&tEnd, NULL); 84 | double elapsedTime = (tEnd.tv_sec - tBegin.tv_sec) * 1000.0; // sec to ms 85 | elapsedTime += (tEnd.tv_usec - tBegin.tv_usec) / 1000.0; // us to ms 86 | cout << elapsedTime << " ms.\n"; 87 | 88 | double vm, rss; 89 | process_mem_usage(vm, rss); 90 | cout << "VM: " << vm << "; RSS: " << rss << endl; 91 | } 92 | 93 | void test(char *argv[]) { 94 | Graph G(atoi(argv[1]), true); 95 | IO::scanEZ(G); 96 | // IO::scan(G); 97 | // removeAllEdges(G); 98 | graphInfo(G); 99 | 100 | // // Graph O = G; 101 | // Graph O = removeZerosLoopsParallels(G); 102 | // graphInfo(O); 103 | 104 | // G.insert(); 105 | // G.insert(); 106 | // graphInfo(G); 107 | // // // cout << "zeros: " << G.zeros() << " | " << zeros(G) << endl; 108 | // // // for (int v = 0; v < G.V(); ++v) { 109 | // // // cout << v << ": " << G.degree(v) << endl; 110 | // // // } 111 | 112 | // G.remove(0); 113 | // graphInfo(G); 114 | 115 | // findMaxSeqClique(G); 116 | 117 | // cout << "sPATH = " << sPATH(G, 1, 2).exist() << endl; 118 | // cout << "gPATH = " << gPATH(G, 1, 2).exist() << endl; 119 | // ePATH ep(G, 1, 2); 120 | // cout << "ePATH = " << ep.exist() << endl; 121 | // ep.show(); 122 | 123 | // SC sc(G); 124 | // for (int i = 0; i < G.V(); ++i) { 125 | // cout << " " << sc.ID(i); 126 | // } 127 | // cout << endl; 128 | } 129 | 130 | int main(int argc, char *argv[]) { 131 | // measure(argv); 132 | test(argv); 133 | 134 | return 0; 135 | } -------------------------------------------------------------------------------- /cpp/first_half/main_17-6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "GRAPH.cc" 4 | #include "IO.cc" 5 | #include "CC.cc" 6 | 7 | using namespace std; 8 | 9 | // Программа 17.6. Пример клиентской программы обработки графов 10 | int main(int argc, char *argv[]) { 11 | int V = atoi(argv[1]); 12 | GRAPH G(V); 13 | IO::scan(G); 14 | if (V < 20) IO::show(G); 15 | cout << G.E() << " edges "; 16 | CC Gcc(G); 17 | cout << Gcc.count() << " components" << endl; 18 | return 0; 19 | } -------------------------------------------------------------------------------- /cpp/first_half/process_mem_usage.cc: -------------------------------------------------------------------------------- 1 | #include "process_mem_usage.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void process_mem_usage(double& vm_usage, double& resident_set) 8 | { 9 | using std::ios_base; 10 | using std::ifstream; 11 | using std::string; 12 | 13 | vm_usage = 0.0; 14 | resident_set = 0.0; 15 | 16 | // 'file' stat seems to give the most reliable results 17 | // 18 | ifstream stat_stream("/proc/self/stat",ios_base::in); 19 | 20 | // dummy vars for leading entries in stat that we don't care about 21 | // 22 | string pid, comm, state, ppid, pgrp, session, tty_nr; 23 | string tpgid, flags, minflt, cminflt, majflt, cmajflt; 24 | string utime, stime, cutime, cstime, priority, nice; 25 | string O, itrealvalue, starttime; 26 | 27 | // the two fields we want 28 | // 29 | unsigned long vsize; 30 | long rss; 31 | 32 | stat_stream >> pid >> comm >> state >> ppid >> pgrp >> session >> tty_nr 33 | >> tpgid >> flags >> minflt >> cminflt >> majflt >> cmajflt 34 | >> utime >> stime >> cutime >> cstime >> priority >> nice 35 | >> O >> itrealvalue >> starttime >> vsize >> rss; // don't care about the rest 36 | 37 | stat_stream.close(); 38 | 39 | long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; // in case x86-64 is configured to use 2MB pages 40 | vm_usage = vsize / 1024.0; 41 | resident_set = rss * page_size_kb; 42 | } 43 | -------------------------------------------------------------------------------- /cpp/first_half/process_mem_usage.h: -------------------------------------------------------------------------------- 1 | #ifndef PROCESS_MEM_USAGE_H 2 | #define PROCESS_MEM_USAGE_H 3 | 4 | ////////////////////////////////////////////////////////////////////////////// 5 | // 6 | // process_mem_usage(double &, double &) - takes two doubles by reference, 7 | // attempts to read the system-dependent data for a process' virtual memory 8 | // size and resident set size, and return the results in KB. 9 | // 10 | // On failure, returns 0.0, 0.0 11 | 12 | void process_mem_usage(double& vm_usage, double& resident_set); 13 | 14 | #endif // PROCESS_MEM_USAGE_H 15 | -------------------------------------------------------------------------------- /cpp/first_half/sPATH.cc: -------------------------------------------------------------------------------- 1 | #ifndef SPATH_CC_ 2 | #define SPATH_CC_ 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | // Программа 17.16. Поиск простого пути 9 | template 10 | class sPATH { 11 | const Graph &G; 12 | vector visited; 13 | bool found; 14 | 15 | bool searchR(int v, int w) { 16 | if (v == w) return true; 17 | visited[v] = true; 18 | typename Graph::adjIterator A(G, v); 19 | for (int t = A.beg(); !A.end(); t = A.nxt()) { 20 | if (!visited[t] && searchR(t, w)) return true; 21 | } 22 | return false; 23 | } 24 | 25 | public: 26 | sPATH(const Graph &G, int v, int w) : G(G), visited(G.V(), false) { 27 | found = searchR(v, w); 28 | } 29 | 30 | bool exist() const { 31 | return found; 32 | } 33 | }; 34 | 35 | #endif -------------------------------------------------------------------------------- /cpp/first_half/tc.cc: -------------------------------------------------------------------------------- 1 | #ifndef TC_DFS_CC_ 2 | #define TC_DFS_CC_ 3 | 4 | #include "Edge.cc" 5 | 6 | // Программа 19.4. Транзитивное замыкание, построенное на основе поиска в глубину 7 | template 8 | class tc { 9 | const Graph &G; 10 | Graph T; 11 | 12 | void tcR(int v, int w) { 13 | T.insert(Edge(v, w)); 14 | typename Graph::adjIterator A(G, w); 15 | for (int t = A.beg(); !A.end(); t = A.nxt()) { 16 | if (!T.edge(v, t)) tcR(v, t); 17 | } 18 | } 19 | 20 | public: 21 | tc(const Graph &G) : G(G), T(G.V(), true) { 22 | for (int v = 0; v < G.V(); ++v) tcR(v, v); 23 | } 24 | 25 | bool reachable(int s, int t) const { 26 | return T.edge(s, t); 27 | } 28 | }; 29 | 30 | #endif -------------------------------------------------------------------------------- /cpp/second_half/DenseGRAPH.cc: -------------------------------------------------------------------------------- 1 | #ifndef DENSEGRAPH_CC_ 2 | #define DENSEGRAPH_CC_ 3 | 4 | #include 5 | using namespace std; 6 | 7 | // Программа 20.3 (обновлённая). Класс взвешенного графа (представление в виде матрицы смежности) 8 | template 9 | class DenseGRAPH { 10 | int Vcnt, Ecnt; 11 | bool digraph; 12 | vector< vector > adj; 13 | 14 | public: 15 | DenseGRAPH(int V, bool digraph = false) : adj(V), Vcnt(V), Ecnt(0), digraph(digraph) { 16 | for (int i = 0; i < V; i++) { 17 | adj[i].assign(V, (Edge *)0); 18 | } 19 | } 20 | 21 | ~DenseGRAPH() { 22 | for (int v = 0; v < Vcnt; v++) { 23 | for (int w = 0; w < Vcnt; w++) { 24 | if (adj[v][w]) { 25 | delete adj[v][w]; 26 | // adj[v][w] = 0; 27 | if (!digraph) adj[w][v] = 0; 28 | } 29 | } 30 | } 31 | } 32 | 33 | int V() const { return Vcnt; } 34 | int E() const { return Ecnt; } 35 | bool directed() const { return digraph; } 36 | 37 | void insert(Edge *e) { 38 | int v = e->v(), w = e->w(); 39 | if (adj[v][w] == 0) Ecnt++; 40 | adj[v][w] = e; 41 | if (!digraph) adj[w][v] = e; 42 | } 43 | 44 | void remove(Edge *e) { 45 | int v = e->v(), w = e->w(); 46 | if (adj[v][w] != 0) { 47 | delete adj[v][w]; 48 | Ecnt--; 49 | } 50 | adj[v][w] = 0; 51 | if (!digraph) { 52 | if (adj[w][v]) delete adj[w][v]; 53 | adj[w][v] = 0; 54 | } 55 | } 56 | 57 | Edge *edge(int v, int w) const { 58 | return adj[v][w]; 59 | } 60 | 61 | class adjIterator; 62 | friend class adjIterator; 63 | }; 64 | 65 | // Программа 20.4. Класс итератора, ориентированный на представление графа в виде матрицы смежности 66 | template 67 | class DenseGRAPH::adjIterator { 68 | const DenseGRAPH &G; 69 | int i, v; 70 | 71 | public: 72 | adjIterator(const DenseGRAPH &G, int v) : G(G), v(v), i(0) {} 73 | 74 | Edge *beg() { 75 | i = -1; 76 | return nxt(); 77 | } 78 | 79 | Edge *nxt() { 80 | for (i++; i < G.V(); i++) { 81 | if (G.edge(v, i)) return G.adj[v][i]; 82 | } 83 | return 0; 84 | } 85 | 86 | bool end() const { 87 | return i >= G.V(); 88 | } 89 | }; 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /cpp/second_half/EDGE.cc: -------------------------------------------------------------------------------- 1 | #ifndef EDGE_CC_ 2 | #define EDGE_CC_ 3 | 4 | // Программа 20.1. Интерфейс АДТ взвешенного ребра 5 | 6 | class EDGE { 7 | public: 8 | EDGE(int, int, double); 9 | int v() const; 10 | int w() const; 11 | double wt() const; 12 | bool from(int) const; 13 | int other(int) const; 14 | }; 15 | 16 | #endif -------------------------------------------------------------------------------- /cpp/second_half/GRAPH.cc: -------------------------------------------------------------------------------- 1 | #ifndef GRAPH_CC_ 2 | #define GRAPH_CC_ 3 | 4 | // Программа 20.1. Интерфейс АДТ графа со взвешенными рёбрами 5 | 6 | template 7 | class GRAPH { 8 | public: 9 | GRAPH(int, bool); 10 | ~GRAPH(); 11 | 12 | int V() const; 13 | int E() const; 14 | bool directed() const; 15 | 16 | int insert(Edge *); 17 | int remove(Edge *); 18 | Edge *edge(int, int); 19 | 20 | class adjIterator { 21 | adjIterator(const GRAPH &, int); 22 | Edge *beg(); 23 | Edge *nxt(); 24 | bool end(); 25 | }; 26 | }; 27 | 28 | #endif -------------------------------------------------------------------------------- /cpp/second_half/IO.cc: -------------------------------------------------------------------------------- 1 | #ifndef IO_CC_ 2 | #define IO_CC_ 3 | 4 | #include 5 | #include "clients.cc" 6 | #include "../first_half/ST.cc" 7 | 8 | // Упражнение 20.9 9 | template 10 | class IO { 11 | public: 12 | static void show(const Graph &G); 13 | static void showEdges(const Graph &G); 14 | static void showAdj(const Graph &G); 15 | 16 | static void scanEZ(Graph &G); 17 | static void scan(Graph &G); 18 | 19 | private: 20 | static bool isTerminateInput(int deep = 2); 21 | }; 22 | 23 | template 24 | void IO::show(const Graph &G) { 25 | for (int s = 0; s < G.V(); s++) { 26 | cout.width(2); 27 | cout << s << ": "; 28 | typename Graph::adjIterator A(G, s); 29 | for (Edge *e = A.beg(); !A.end(); e = A.nxt()) { 30 | cout.width(2); 31 | cout << e->other(s); 32 | e->wt(cout) << " -> "; 33 | } 34 | cout << endl; 35 | } 36 | cout << endl; 37 | } 38 | 39 | template 40 | void IO::showEdges(const Graph &G) { 41 | const vector vec = edges(G); 42 | for (typename vector::const_iterator p = vec.begin(); p != vec.end(); ++p) { 43 | (*p)->show(); 44 | } 45 | } 46 | 47 | template 48 | void IO::showAdj(const Graph &G) { 49 | const int DEFAULT_WIDTH = 5; 50 | 51 | for (int i = 0; i < DEFAULT_WIDTH; i++) cout << ' '; 52 | cout << " |"; 53 | for (int i = 0; i < G.V(); i++) { 54 | cout.width(DEFAULT_WIDTH); 55 | cout << i; 56 | } 57 | cout << endl; 58 | for (int i = 0; i <= G.V(); i++) { 59 | for (int j = 0; j < DEFAULT_WIDTH; j++) cout << '-'; 60 | } 61 | cout << "--" << endl; 62 | 63 | for (int v = 0; v < G.V(); v++) { 64 | cout.width(DEFAULT_WIDTH); 65 | cout << v << " |"; 66 | 67 | for (int w = 0; w < G.V(); w++) { 68 | cout << " "; 69 | G.edge(v, w) ? G.edge(v, w)->wt(cout) : (cout << " *"); 70 | } 71 | cout << endl; 72 | } 73 | cout << endl; 74 | } 75 | 76 | template 77 | void IO::scanEZ(Graph &G) { 78 | int v, w; 79 | double wt; 80 | while (!isTerminateInput()) { 81 | cin >> v >> w >> wt; 82 | if (v < 0 || v >= G.V() || w < 0 || w >= G.V()) { 83 | cerr << "Out of range" << endl; 84 | continue; 85 | } 86 | G.insert(new Edge(v, w, wt)); 87 | } 88 | } 89 | 90 | template 91 | void IO::scan(Graph &G) { 92 | string v, w; 93 | double wt; 94 | ST st; 95 | while (!isTerminateInput()) { 96 | cin >> v >> w; 97 | G.insert(new Edge(st.index(v), st.index(w), wt)); 98 | } 99 | } 100 | 101 | template 102 | bool IO::isTerminateInput(int deep) { 103 | if (deep == 0) return true; 104 | char c = cin.get(); 105 | if (c == '\n') return isTerminateInput(deep - 1); 106 | else cin.putback(c); 107 | return false; 108 | } 109 | 110 | #endif 111 | -------------------------------------------------------------------------------- /cpp/second_half/MSTbr.cc: -------------------------------------------------------------------------------- 1 | #ifndef MSTBR_CC_ 2 | #define MSTBR_CC_ 3 | 4 | #include 5 | #include "clients.cc" 6 | using namespace std; 7 | 8 | // Программа 20.9. Алгоритм Борувки построения дерева MST 9 | template 10 | class MSTbr { 11 | const Graph &G; 12 | vector a, b, mst; 13 | UF uf; 14 | 15 | public: 16 | MSTbr(const Graph &G) : G(G), mst(G.V()), uf(G.V()) { 17 | a = edges(G); 18 | int N = -1, k = 0; 19 | for (int E = a.size(); E != 0; E = N) { 20 | int h, i, j; 21 | b.assign(G.V(), (Edge *)0); 22 | for (h = 0, N = 0; h < E; h++) { 23 | Edge *e = a[h]; 24 | i = uf.find(e->v()), j = uf.find(e->w()); 25 | if (i == j) continue; 26 | if (!b[i] || e->wt() < b[i]->wt()) b[i] = e; 27 | if (!b[j] || e->wt() < b[j]->wt()) b[j] = e; 28 | a[N++] = e; 29 | } 30 | for (h = 0; h < G.V(); h++) { 31 | if (b[h] && !uf.find(i = b[h]->v(), j = b[h]->w())) { 32 | uf.unite(i, j); 33 | mst[k++] = b[h]; 34 | } 35 | } 36 | } 37 | } 38 | 39 | void show() { 40 | for (int v = 0; v < G.V(); ++v) { 41 | if (mst[v]) mst[v]->show(); 42 | } 43 | } 44 | }; 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /cpp/second_half/MSTcr.cc: -------------------------------------------------------------------------------- 1 | #ifndef MSTCR_CC_ 2 | #define MSTCR_CC_ 3 | 4 | #include 5 | #include 6 | #include "clients.cc" 7 | #include "UF.cc" 8 | 9 | // Программа 20.8 (обновлённая). Алгоритм Крускала, обеспечивающий построение дерева MST 10 | template 11 | class MSTcr { 12 | const Graph &G; 13 | vector a, mst; 14 | UF uf; 15 | 16 | struct Compare { 17 | bool operator() (const Edge *a, const Edge *b) { 18 | return a->wt() < b->wt(); 19 | } 20 | }; 21 | 22 | public: 23 | MSTcr(const Graph &G) : G(G), mst(G.V()), uf(G.V()) { 24 | int V = G.V(), E = G.E(); 25 | a = edges(G); 26 | sort(a.begin(), a.end(), Compare()); 27 | for (int i = 0, k = 1; i < E && k < V; i++) { 28 | if (!uf.find(a[i]->v(), a[i]->w())) { 29 | uf.unite(a[i]->v(), a[i]->w()); 30 | mst[k++] = a[i]; 31 | } 32 | } 33 | } 34 | 35 | void show() { 36 | for (int v = 1; v < G.V(); ++v) { 37 | if (mst[v]) mst[v]->show(); 38 | } 39 | } 40 | }; 41 | 42 | #endif -------------------------------------------------------------------------------- /cpp/second_half/MSTpr.cc: -------------------------------------------------------------------------------- 1 | #ifndef MSTPR_CC_ 2 | #define MSTPR_CC_ 3 | 4 | #include 5 | 6 | // Программа 20.6. Алгоритм Прима, реализующий построение дерева MST 7 | template 8 | class MSTpr { 9 | const Graph &G; 10 | vector wt; 11 | vector fr, mst; 12 | 13 | public: 14 | MSTpr(const Graph &G) : G(G), wt(G.V(), G.V()), fr(G.V()), mst(G.V()) { 15 | int min = -1; 16 | for (int v = 0; min != 0; v = min) { 17 | min = 0; 18 | for (int w = 1; w < G.V(); w++) { 19 | if (mst[w] == 0) { 20 | double P; 21 | Edge *e = G.edge(v, w); 22 | if (e && (P = e->wt()) < wt[w]) { 23 | wt[w] = P; 24 | fr[w] = e; 25 | } 26 | if (wt[w] < wt[min]) min = w; 27 | } 28 | } 29 | if (min) mst[min] = fr[min]; 30 | } 31 | } 32 | 33 | void show() { 34 | for (int v = 1; v < G.V(); ++v) { 35 | if (mst[v]) mst[v]->show(); 36 | } 37 | } 38 | }; 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /cpp/second_half/PQi.cc: -------------------------------------------------------------------------------- 1 | #ifndef PQI_CC_ 2 | #define PQI_CC_ 3 | 4 | #include 5 | using namespace std; 6 | 7 | // Программа 20.10. Реализация очереди с приоритетами в виде многопозиционного частично упорядоченного полного дерева 8 | template 9 | class PQi { 10 | const vector &a; 11 | vector pq, qp; 12 | int d, N; 13 | 14 | void exch(int i, int j) { 15 | int t = pq[i]; 16 | pq[i] = pq[j]; 17 | pq[j] = t; 18 | qp[pq[i]] = i; 19 | qp[pq[j]] = j; 20 | } 21 | 22 | void fixUp(int k) { 23 | int kd; 24 | while (k > 1 && a[(kd = pq[(k+d-2)/d)]] > a[pq[k]]) { 25 | exch(k, kd); 26 | k = kd; 27 | } 28 | } 29 | 30 | void fixDown(int k, int N) { 31 | int j; 32 | while ((j = d*(k-1)+2) <= N) { 33 | for (int i = j+1; i < j+d && i <= N; i++) { 34 | if (a[pq[j]] > a[pq[i]]) j = i; 35 | } 36 | if (!(a[pq[k]] > a[pq[j]])) break; 37 | exch(k, j); 38 | k = j; 39 | } 40 | } 41 | 42 | public: 43 | PQi(int N, const vector &a, int d = 3) : 44 | a(a), pq(N+1, 0), qp(N+1, 0), N(0), d(d) {} 45 | 46 | int empty() const { return N == 0; } 47 | 48 | void insert(int v) { 49 | pq[++N] = v; 50 | qp[v] = N; 51 | fixUp(N); 52 | } 53 | 54 | int getmin() { 55 | exch(1, N); 56 | fixDown(1, N-1); 57 | return pq[N--]; 58 | } 59 | 60 | void lower(int k) { 61 | fixUp(qp[k]); 62 | } 63 | }; 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /cpp/second_half/SparseMultiGRAPH.cc: -------------------------------------------------------------------------------- 1 | #ifndef SPARSEMULTIGRAPH_CC_ 2 | #define SPARSEMULTIGRAPH_CC_ 3 | 4 | #include 5 | 6 | // Программа 20.5. Класс взвешенного графа (списки смежных вершин) 7 | template 8 | class SparseMultiGRAPH { 9 | int Vcnt, Ecnt; 10 | bool digraph; 11 | struct node { 12 | Edge *e; 13 | node *next; 14 | node(Edge *e, node *next) : e(e), next(next) {} 15 | }; 16 | typedef node * link; 17 | vector adj; 18 | 19 | public: 20 | SparseMultiGRAPH(int V, bool digraph = false) : 21 | adj(V), Vcnt(V), Ecnt(0), digraph(digraph) {} 22 | ~SparseMultiGRAPH() { 23 | for (int v = 0; v < Vcnt; ++v) { 24 | link t = adj[v], prev; 25 | while (t) { 26 | prev = t; 27 | t = t->next; 28 | delete prev; 29 | } 30 | } 31 | } 32 | 33 | int V() const { return Vcnt; } 34 | int E() const { return Ecnt; } 35 | bool directed() const { return digraph; } 36 | 37 | void insert(Edge *e) { 38 | adj[e->v()] = new node(e, adj[e->v()]); 39 | if (!digraph) { 40 | adj[e->w()] = new node(e, adj[e->w()]); 41 | } 42 | Ecnt++; 43 | } 44 | 45 | class adjIterator; 46 | friend class adjIterator; 47 | }; 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /cpp/second_half/UF.cc: -------------------------------------------------------------------------------- 1 | #ifndef UF_CC_ 2 | #define UF_CC_ 3 | 4 | // Программа 4.11. Реализация АДТ "Отношения эквивалентности" 5 | class UF { 6 | int *id, *sz; 7 | 8 | public: 9 | UF(int N) { 10 | id = new int[N]; 11 | sz = new int[N]; 12 | for (int i = 0; i < N; i++) { 13 | id[i] = i; 14 | sz[i] = 1; 15 | } 16 | } 17 | 18 | ~UF() { 19 | delete [] sz; 20 | delete [] id; 21 | } 22 | 23 | int find(int x) const { 24 | while (x != id[x]) x = id[x]; 25 | return x; 26 | } 27 | 28 | int find(int p, int q) const { 29 | return (find(p) == find(q)); 30 | } 31 | 32 | void unite(int p, int q) { 33 | int i = find(p), j = find(q); 34 | if (i == j) return; 35 | if (sz[i] < sz[j]) { 36 | id[i] = j; 37 | sz[j] += sz[i]; 38 | } else { 39 | id[j] = i; 40 | sz[i] += sz[j]; 41 | } 42 | } 43 | }; 44 | 45 | #endif -------------------------------------------------------------------------------- /cpp/second_half/WeightedEdge.cc: -------------------------------------------------------------------------------- 1 | #ifndef WEIGHTEDEDGE_CC_ 2 | #define WEIGHTEDEDGE_CC_ 3 | 4 | #include 5 | using namespace std; 6 | 7 | // Упражнение 20.8 8 | class WeightedEdge { 9 | int _v, _w; 10 | double _wt; 11 | 12 | public: 13 | WeightedEdge(int v, int w, double wt) : _v(v), _w(w), _wt(wt) {} 14 | 15 | int v() const { return _v; } 16 | int w() const { return _w; } 17 | double wt() const { return _wt; } 18 | 19 | bool from(int v) const { return _v == v; } 20 | int other(int v) const { return from(v) ? _w : _v; } 21 | 22 | void show() const { 23 | cout << _v << "-" << _w; 24 | wt(cout) << endl; 25 | } 26 | 27 | ostream &wt(ostream &os) const { 28 | os << " ." << (int)(_wt * 100 + 0.5); 29 | return os; 30 | } 31 | }; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /cpp/second_half/a.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newmen/graph-algorithms/7314950ccf1050c16b5dfb3d40a6d6864c74cd9b/cpp/second_half/a.out -------------------------------------------------------------------------------- /cpp/second_half/clients.cc: -------------------------------------------------------------------------------- 1 | #ifndef CLIENTS_CC_ 2 | #define CLIENTS_CC_ 3 | 4 | #include 5 | 6 | // Программа 20.2. Пример клиентской функции обработки графа 7 | template 8 | vector edges(const Graph &G) { 9 | int E = 0; 10 | vector a(G.E()); 11 | for (int v = 0; v < G.V(); v++) { 12 | typename Graph::adjIterator A(G, v); 13 | for (Edge *e = A.beg(); !A.end(); e = A.nxt()) { 14 | if (e->from(v)) a[E++] = e; 15 | } 16 | } 17 | return a; 18 | } 19 | 20 | #endif -------------------------------------------------------------------------------- /cpp/second_half/inputs.txt: -------------------------------------------------------------------------------- 1 | 8 2 | 0 6 0.51 3 | 0 1 0.32 4 | 0 2 0.29 5 | 4 3 0.34 6 | 5 3 0.18 7 | 7 4 0.46 8 | 5 4 0.4 9 | 0 5 0.6 10 | 6 4 0.51 11 | 7 0 0.31 12 | 7 6 0.25 13 | 7 1 0.21 14 | -------------------------------------------------------------------------------- /cpp/second_half/main.cc: -------------------------------------------------------------------------------- 1 | #include "WeightedEdge.cc" 2 | #include "DenseGRAPH.cc" 3 | #include "SparseMultiGRAPH.cc" 4 | #include "IO.cc" 5 | 6 | #include "MSTpr.cc" 7 | #include "MSTcr.cc" 8 | #include "MSTbr.cc" 9 | 10 | typedef WeightedEdge Edge; 11 | typedef DenseGRAPH Graph; 12 | 13 | void graphInfo(const Graph &G) { 14 | // IO::show(G); 15 | // IO::showEdges(G); 16 | IO::showAdj(G); 17 | } 18 | 19 | int main() { 20 | int V; 21 | cin >> V; 22 | Graph G(V); 23 | 24 | IO::scanEZ(G); 25 | MSTbr(G).show(); 26 | 27 | // graphInfo(G); 28 | 29 | return 0; 30 | } -------------------------------------------------------------------------------- /cpp/second_half/sort.cc: -------------------------------------------------------------------------------- 1 | #ifndef SORT_CC_ 2 | #define SORT_CC_ 3 | 4 | // Программа 6.1. Пример сортировки массива с помощью управляющей программы 5 | 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | template 11 | void exch(Item &A, Item &B) { 12 | Item t = A; 13 | A = B; 14 | B = t; 15 | } 16 | 17 | template 18 | void complexch(Item &A, Item &B) { 19 | if (B < A) exch(A, B); 20 | } 21 | 22 | template 23 | void sort(Item a[], int l, int r) { 24 | for (int i = l + 1; i <= r; i++) { 25 | for (int j = i; j < l; j--) { 26 | complexch(a[j - 1], a[j]); 27 | } 28 | } 29 | } 30 | 31 | #endif 32 | 33 | // int main(int argc, char *argv[]) { 34 | // int i, N = atoi(argv[1]), sw = atoi(argv[2]); 35 | // int *a = new int[N]; 36 | // if (sw) { 37 | // for (i = 0; i < N; i++) { 38 | // a[i] = 1000 * (1.0 * rand() / RAND_MAX); 39 | // } 40 | // } else { 41 | // N = 0; 42 | // while (cin >> a[N]) N++; 43 | // } 44 | 45 | // sort(a, 0, N - 1); 46 | 47 | // for (i = 0; i < N; i++) cout << a[i] << " "; 48 | // cout << endl; 49 | // } 50 | -------------------------------------------------------------------------------- /ruby/basic.rb: -------------------------------------------------------------------------------- 1 | def max_edges_num(vertex_num) 2 | vertex_num * (vertex_num - 1) / 2 3 | end 4 | 5 | def max_graphs_num(vertex_num) 6 | 2 ** max_edges_num(vertex_num) 7 | end 8 | 9 | -------------------------------------------------------------------------------- /ruby/generator.rb: -------------------------------------------------------------------------------- 1 | def edge(v, w) 2 | "#{v} #{w}" 3 | end 4 | 5 | def sparse(v, e) 6 | p = 2.0 * e / (v * (v - 1)) 7 | result = [] 8 | 100.times do |i| 9 | i.times do |j| 10 | result << edge(i, j) if rand < p 11 | end 12 | end 13 | result 14 | end 15 | 16 | def dense(v) 17 | [*0...v].combination(2).map { |a, b| edge(a, b) } 18 | end 19 | 20 | def write(filename, edges) 21 | File.open(filename, 'w') do |f| 22 | f.write(edges.join(' ')) 23 | f.write("\n\n") 24 | end 25 | end 26 | 27 | write('sparse.txt', sparse(1000, 5000)) 28 | -------------------------------------------------------------------------------- /ruby/hash.rb: -------------------------------------------------------------------------------- 1 | require 'benchmark' 2 | 3 | N = 1000 4 | # M = N * N 5 | M = ((1 + N) * N * 0.5).to_i 6 | 7 | def check(hash_func_name, each_inform = true) 8 | checker = {} 9 | has_error = 0 10 | (0..N).each do |i| 11 | b = (M == N * N) ? 0 : i 12 | (b..N).each do |j| 13 | h = send(hash_func_name, i, j) 14 | if checker[h] 15 | has_error += 1 16 | puts "#{hash_func_name}(#{i}, #{j}) = #{h}" if each_inform 17 | else 18 | checker[h] = true 19 | end 20 | end 21 | end 22 | "#{hash_func_name} conflicts: #{has_error} (#{100.0 * has_error / (M)}%)" 23 | end 24 | 25 | def h_and(i, j); i & j; end 26 | def h_3and(i, j); i & j & (M - 1); end 27 | 28 | def m_str(i, j, m) 29 | h = i % m 30 | (h * N + j) % m 31 | end 32 | 33 | def h_str(i, j); m_str(i, j, M); end 34 | def h_ustr(i, j); m_str(i, j, M + 1); end 35 | def h_dstr(i, j); m_str(i, j, M - 1); end 36 | def h_lstr(i, j); m_str(i, j, M * 2); end 37 | def h_llstr(i, j); m_str(i, j, M * 10); end 38 | 39 | def h_rnd(i, j) 40 | a, b = 31415, 27183 41 | [i, j].inject(0) do |h, x| 42 | a = a * b % (M - 1) 43 | h = (a * h + x) % M 44 | end 45 | end 46 | 47 | def h_pair(i, j); "#{i}-#{j}"; end 48 | 49 | def h_xor(i, j); i ^ j; end 50 | def h_seek(i, j); j + 0x9e3779b9 + (i << 6) + (i >> 2); end 51 | def h_or_seek(i, j); (i << 19) | (j << 7); end # 1 52 | def h_seek_or_and(i, j); (i << 16) | (j & 0xffff); end # 4 53 | def h_mul_xor(i, j); (i * 0x1f1f1f1f) ^ j; end 54 | def h_cantor(i, j); ((i + j) * (i + j + 1) / 2) + j; end # 3 55 | def h_seek_xor(i, j); (j << 16) ^ i; end # 2 56 | def h_and_seek_or_and(i, j); ((j & 0xffff) << 16) | (i & 0xffff); end # 5 57 | 58 | bad = %w( h_and h_3and h_str h_ustr h_dstr h_rnd h_xor h_seek ) 59 | good = %w( h_lstr h_llstr h_pair h_mul_xor ) 60 | best = %w( h_or_seek h_seek_or_and h_cantor h_seek_xor h_and_seek_or_and ) 61 | 62 | best.each do |hash_func_name| 63 | msg = nil 64 | bm = Benchmark.measure { msg = check(hash_func_name, N < 11) } 65 | puts "#{msg.ljust(50)} -> #{bm}" 66 | end 67 | -------------------------------------------------------------------------------- /ruby/mm.rb: -------------------------------------------------------------------------------- 1 | BASE = [ 2 | %w(0 0 1 0 0 1), 3 | %w(1 0 0 0 0 0), 4 | %w(0 1 0 0 0 0), 5 | %w(0 0 1 0 1 0), 6 | %w(0 0 0 0 0 1), 7 | %w(0 0 0 0 1 0) 8 | ] 9 | 10 | def make_bmatrix 11 | i = 0 12 | BASE.map do |row| 13 | i, j = i + 1, 0 14 | row.map do |x| 15 | j += 1 16 | x == '1' || (block_given? && yield(i - 1, j - 1)) 17 | end 18 | end 19 | end 20 | 21 | def sq_bmatrix(a, b) 22 | result = Array.new(a.size) { Array.new(a.size, false) } 23 | a.size.times do |s| 24 | a.size.times do |t| 25 | a.size.times { |i| result[s][t] ||= a[s][i] && b[i][t] } 26 | end 27 | end 28 | result 29 | end 30 | 31 | def print_bmatrix(matrix) 32 | matrix.each do |row| 33 | row.each do |x| 34 | print (x ? '1' : '0').rjust(2) 35 | end 36 | puts 37 | end 38 | puts 39 | end 40 | 41 | def mul_bmarix(name, matrix, depth, prev_result = nil) 42 | @depth = depth unless prev_result 43 | 44 | puts "#{name} ** #{@depth - depth + 1}:" 45 | prev_result ||= matrix 46 | print_bmatrix(prev_result) 47 | return if depth == 1 48 | mul_bmarix(name, matrix, depth - 1, sq_bmatrix(prev_result, matrix)) 49 | end 50 | 51 | az = make_bmatrix 52 | mul_bmarix('AZ', az, 20) 53 | 54 | puts '-' * BASE.size * 2 55 | puts 56 | 57 | ao = make_bmatrix { |i, j| i == j } 58 | mul_bmarix('AO', ao, 5) 59 | --------------------------------------------------------------------------------