├── .github └── workflows │ └── ci_test.yml ├── GUIDEBOOK.md ├── LICENSE ├── README.md ├── demo.cpp ├── image ├── binary.png ├── chain.png ├── complete.png ├── completebinary.png ├── demo1.png ├── demo2.png ├── demo3.png ├── lowhigh.png ├── maxdegree.png ├── random.png ├── silkworm.png ├── star.png └── tall.png ├── tests ├── check.cpp └── test.cpp └── treegenerator.h /.github/workflows/ci_test.yml: -------------------------------------------------------------------------------- 1 | name: "CI Test" 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - '*.md' 7 | pull_request: 8 | paths-ignore: 9 | - '*.md' 10 | 11 | jobs: 12 | build: 13 | name: "CI Test on ${{ matrix.os }}" 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | os: [ubuntu-latest, windows-latest, ubuntu-16.04] 19 | 20 | steps: 21 | - uses: actions/checkout@v2 22 | 23 | - name: "Run tests" 24 | shell: bash 25 | run: | 26 | cd tests 27 | g++ -std=c++11 -I .. -o test test.cpp 28 | g++ -std=c++11 -o check check.cpp 29 | ./test > test.out 30 | ./check < test.out 31 | -------------------------------------------------------------------------------- /GUIDEBOOK.md: -------------------------------------------------------------------------------- 1 | ## Header file and namespace 2 | 3 | ```cpp 4 | #include "treegenerator.h" 5 | ``` 6 | 7 | Please put the file `treegenerator.h` in the same folder as your .cpp source file, or use the compile option `-I `. 8 | 9 | ```cpp 10 | using namespace tree_generator_by_ouuan; 11 | ``` 12 | 13 | Of course, you can also use `tree_generator_by_ouuan::` when necessary. 14 | 15 | ## Declare a tree 16 | 17 | ```cpp 18 | Tree t; // a tree with a single node 19 | Tree t(10); // a random tree with 10 nodes 20 | Tree t("ch9,0"); // a tree with 10 nodes in the shape of a chain, see "Generate trees by strings" for more details 21 | ``` 22 | 23 | ## Nodes 24 | 25 | The nodes are 0-indexed. (However, the default output function is 1-indexed.) 26 | 27 | You can't declare an empty tree, and the initial single node is numbered 0. 28 | 29 | When adding a new node, it will be numbered n, where n is the size of the tree before adding this node. 30 | 31 | In the following functions, the nodes are added in some BFS order (so are the numbers of the nodes), you can see the codes for the details. 32 | 33 | `void addNode(int pa)`: add a node whose parent is `pa`. 34 | 35 | `void random(int n, int pa)`: add a random tree consisting of n nodes whose root's parent is `pa`. 36 | 37 | ![random(20,0)](image/random.png) 38 | 39 | `void lowhigh(int n, double low, double high, int pa)`: add a random tree consisting of n nodes whose parent is `pa`, the parent of the i-th node is chosen from the interval [(i-1)\*low, (i-1)\*high]. 40 | 41 | ![lowhigh(30,0.1,0.3,0)](image/lowhigh.png) 42 | 43 | `void tall(int n, int k, int pa)`: add a tree consisting of n nodes whose root's parent is `pa`, in which the parent of the node i is random but has no more than k choice. Specifically, only the last k nodes created before i can be the parent of i, except the first k nodes. 44 | 45 | ![tall(20,3,0)](image/tall.png) 46 | 47 | `void chain(int n, int pa)`: the same as `tall(n, 1, pa)`. 48 | 49 | ![chain(10,0)](image/chain.png) 50 | 51 | `void star(int n, int pa)`: add a tree consisting of n nodes whose root's parent is `pa`, and except the root, all nodes' parent is the root. 52 | 53 | `void flower(int n, int pa)`: the same as `star(n, pa)`. This function exists because many Chinese call this kind of tree "chrysanthemum tree". 54 | 55 | ![star(10,0)](image/star.png) 56 | 57 | `void maxDegree(int n, int k, int pa)`: add a random tree consisting of n nodes whose root's parent is `pa`, and all nodes' degrees don't exceed k. 58 | 59 | `void lowhighMaxDegree(int n, int k, double low, double high, int pa)`: lowhigh + maxDegree. 60 | 61 | ![maxDegree(20,4,0)](image/maxdegree.png) 62 | 63 | `void complete(int n, int k, int pa)`: add a complete tree (like complete binary tree) consisting of n nodes whose root's parent of `pa`, and all nodes' degrees don't exceed k. 64 | 65 | ![complete(20,4,0)](image/complete.png) 66 | 67 | `void binary(int n, int pa)`: the same as `maxDegree(n, 3, pa)`. 68 | 69 | ![binary(20,0)](image/binary.png) 70 | 71 | `void completeBinary(int n, int pa)`: the same as `complete(n, 3, pa)`. 72 | 73 | ![completeBinary(20,0)](image/completebinary.png) 74 | 75 | `void silkworm(int n, int pa)`: add a tree consisting of n nodes whose root's parent is `pa`, and it's based on a chain with one extra son for each node. 76 | 77 | ![silkworm(20,0)](image/silkworm.png) 78 | 79 | `void addLeaves(int n, int l, int r)`: add n nodes, whose parents' numbers are in the range [l, r]. 80 | 81 | ## Shuffle 82 | 83 | You can use `shuffleNodes()` to shuffle the nodes, but it only affects the output, the inner number of each node will not change. The function has a parameter `from`, you can use `shuffleNodes(int from)` to shuffle the nodes, then the first `from` nodes (nodes 0 ~ from - 1) will keep unchanged. 84 | 85 | You can use `shuffleEdges()` to reorder the edges. It only affects the output, too. 86 | 87 | ## Generate trees by strings 88 | 89 | Example: `Tree("bi30,0sw20,30fl10,50ch20,0al5,61,80")` 90 | 91 | `void addNode(int pa)`: `nd` 92 | 93 | `void random(int n, int pa)`: `rd,` 94 | 95 | `void lowhigh(int n, double low, double high, int pa)`: `lh,,,` 96 | 97 | `void tall(int n, int k, int pa)`: `tl,,` 98 | 99 | `void chain(int n, int pa)`: `ch,` 100 | 101 | `void star(int n, int pa)`: `st,` 102 | 103 | `void flower(int n, int pa)`: `fl,` 104 | 105 | `void maxDegree(int n, int k, int pa)`: `md,,` 106 | 107 | `void lowhighMaxDegree(int n, int k, double low, double high, int pa)`: `lm,,,,` 108 | 109 | `void complete(int n, int k, int pa)`: `cp,,` 110 | 111 | `void binary(int n, int pa)`: `bi,` 112 | 113 | `void completeBinary(int n, int pa)`: `cb,` 114 | 115 | `void silkworm(int n, int pa)`: `sw,` 116 | 117 | `void addLeaves(int n, int l, int r)`: `al,,` 118 | 119 | ## Customize random function and output function 120 | 121 | Example: 122 | 123 | ```cpp 124 | void myOutputEdge(ostream& os, int u, int pa) 125 | { 126 | os << u + 1 << ' ' << pa + 1 << ' ' << randint(1, 10) << endl; 127 | } 128 | 129 | outputEdge = myOutputEdge; 130 | ``` 131 | 132 | ```cpp 133 | #include "testlib.h" 134 | 135 | int myRandInt(int l, int r) 136 | { 137 | return rnd.next(l, r); 138 | } 139 | 140 | randint = myRandInt; 141 | ``` 142 | 143 | ## Other functions 144 | 145 | `int size()`: return the number of nodes. 146 | 147 | `void resize(int n)`: add leaves if n > size, cut the last size - n nodes and reorder the nodes and edges if n < size. 148 | 149 | `void printEdge(int edgeID, ostream& os = cout)`: print an edge. 150 | 151 | `int parent(int u)`: return the parent of node u. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 ouuan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Tree-Generator 2 | Help problem setters to generate a variety of trees. 3 | 4 | You can generate different trees with few functions or even a string, and customize the output function or the random function. 5 | 6 | It **hasn't** been well-tested yet, so bug reports are welcomed. 7 | 8 | ### How to use? 9 | 10 | Please read the [GUIDEBOOK](/GUIDEBOOK.md). 11 | 12 | ### Demo 13 | 14 | ```cpp 15 | #include "treegenerator.h" 16 | 17 | using namespace std; 18 | using namespace tree_generator_by_ouuan; 19 | 20 | void myOutputEdge(ostream& os, int u, int pa) 21 | { 22 | os << u + 1 << ' ' << pa + 1 << ' ' << randint(1, 10) << endl; 23 | } 24 | 25 | int main() 26 | { 27 | cout << Tree("ch20,0al5,1,20") << endl; 28 | cout << Tree("bi30,0sw20,30fl10,50") << endl; 29 | 30 | Tree t; 31 | t.complete(40, 4, 0); 32 | t.chain(10, 0); 33 | t.shuffleNodes(1); 34 | t.shuffleEdges(); 35 | outputEdge = myOutputEdge; 36 | cout << t << endl; 37 | 38 | return 0; 39 | } 40 | ``` 41 | 42 | ![](image/demo1.png) 43 | 44 | ![](image/demo2.png) 45 | 46 | ![](image/demo3.png) 47 | 48 | (visualization by [CS Academy](https://csacademy.com/app/graph_editor/)) -------------------------------------------------------------------------------- /demo.cpp: -------------------------------------------------------------------------------- 1 | #include "treegenerator.h" 2 | 3 | using namespace std; 4 | using namespace tree_generator_by_ouuan; 5 | 6 | void myOutputEdge(ostream& os, int u, int pa) 7 | { 8 | os << u + 1 << ' ' << pa + 1 << ' ' << randint(1, 10) << endl; 9 | } 10 | 11 | int main() 12 | { 13 | cout << Tree("ch20,0al5,1,20") << endl; 14 | cout << Tree("bi30,0sw20,30fl10,50") << endl; 15 | 16 | Tree t; 17 | t.complete(40, 4, 0); 18 | t.chain(10, 0); 19 | t.shuffleNodes(1); 20 | t.shuffleEdges(); 21 | outputEdge = myOutputEdge; 22 | cout << t << endl; 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /image/binary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ouuan/Tree-Generator/2480a76e79cf36a70f01457880b1b0198c40b9a0/image/binary.png -------------------------------------------------------------------------------- /image/chain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ouuan/Tree-Generator/2480a76e79cf36a70f01457880b1b0198c40b9a0/image/chain.png -------------------------------------------------------------------------------- /image/complete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ouuan/Tree-Generator/2480a76e79cf36a70f01457880b1b0198c40b9a0/image/complete.png -------------------------------------------------------------------------------- /image/completebinary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ouuan/Tree-Generator/2480a76e79cf36a70f01457880b1b0198c40b9a0/image/completebinary.png -------------------------------------------------------------------------------- /image/demo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ouuan/Tree-Generator/2480a76e79cf36a70f01457880b1b0198c40b9a0/image/demo1.png -------------------------------------------------------------------------------- /image/demo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ouuan/Tree-Generator/2480a76e79cf36a70f01457880b1b0198c40b9a0/image/demo2.png -------------------------------------------------------------------------------- /image/demo3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ouuan/Tree-Generator/2480a76e79cf36a70f01457880b1b0198c40b9a0/image/demo3.png -------------------------------------------------------------------------------- /image/lowhigh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ouuan/Tree-Generator/2480a76e79cf36a70f01457880b1b0198c40b9a0/image/lowhigh.png -------------------------------------------------------------------------------- /image/maxdegree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ouuan/Tree-Generator/2480a76e79cf36a70f01457880b1b0198c40b9a0/image/maxdegree.png -------------------------------------------------------------------------------- /image/random.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ouuan/Tree-Generator/2480a76e79cf36a70f01457880b1b0198c40b9a0/image/random.png -------------------------------------------------------------------------------- /image/silkworm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ouuan/Tree-Generator/2480a76e79cf36a70f01457880b1b0198c40b9a0/image/silkworm.png -------------------------------------------------------------------------------- /image/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ouuan/Tree-Generator/2480a76e79cf36a70f01457880b1b0198c40b9a0/image/star.png -------------------------------------------------------------------------------- /image/tall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ouuan/Tree-Generator/2480a76e79cf36a70f01457880b1b0198c40b9a0/image/tall.png -------------------------------------------------------------------------------- /tests/check.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | int main() 9 | { 10 | int n; 11 | 12 | cin >> n; 13 | 14 | vector f(n + 1); 15 | for (int i = 1; i <= n; ++i) f[i] = i; 16 | 17 | function find = [&](int x) { return x == f[x] ? x : f[x] = find(f[x]); }; 18 | 19 | for (int i = 1; i < n; ++i) 20 | { 21 | int u, v; 22 | cin >> u >> v; 23 | assert(find(u) != find(v)); 24 | f[find(v)] = find(u); 25 | } 26 | 27 | return 0; 28 | } -------------------------------------------------------------------------------- /tests/test.cpp: -------------------------------------------------------------------------------- 1 | #include "treegenerator.h" 2 | #include 3 | 4 | using namespace std; 5 | 6 | int main() 7 | { 8 | cout << tree_generator_by_ouuan::Tree("rd100,0lh100,0.1,0.7,77tl100,3,114ch233,6st773,514fl2434,773md114,4,514lm191,9,0.3,0.9,810cp2333,7,666bi666,2434cb666,999sw100,333al1919,114,514nd121"); 9 | 10 | return 0; 11 | } -------------------------------------------------------------------------------- /treegenerator.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | MIT License 4 | 5 | Copyright (c) 2019 ouuan 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | 25 | */ 26 | 27 | // See https://github.com/ouuan/Tree-Generator to get latest version or bug tracker. 28 | 29 | #ifndef TREE_GENERATOR_BY_OUUAN_ 30 | #define TREE_GENERATOR_BY_OUUAN_ 1 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | namespace tree_generator_by_ouuan 45 | { 46 | typedef std::pair pii; 47 | 48 | std::mt19937 defaultRNG(std::chrono::steady_clock::now().time_since_epoch().count()); 49 | 50 | int defaultRandInt(int l, int r) 51 | { 52 | int out = defaultRNG() % (r - l + 1) + l; 53 | return out >= l ? out : out + r - l + 1; 54 | } 55 | 56 | int (*randint)(int, int) = defaultRandInt; 57 | 58 | void defaultOutputEdge(std::ostream& os, int u, int pa) 59 | { 60 | if (randint(0, 1) == 0) os << u + 1 << ' ' << pa + 1 << std::endl; 61 | else os << pa + 1 << ' ' << u + 1 << std::endl; 62 | } 63 | 64 | void (*outputEdge)(std::ostream&, int, int) = defaultOutputEdge; 65 | 66 | class Tree 67 | { 68 | private: 69 | std::vector p, id, eid; 70 | 71 | public: 72 | Tree() 73 | { 74 | p.push_back(-1); 75 | id.push_back(0); 76 | } 77 | Tree(int n) 78 | { 79 | assert(n > 0); 80 | p.push_back(-1); 81 | id.push_back(0); 82 | if (n > 1) random(n - 1, 0); 83 | } 84 | Tree(const std::string& s) 85 | { 86 | p.push_back(-1); 87 | id.push_back(0); 88 | 89 | std::function findComma = [](const std::string& str, unsigned int sta) 90 | { 91 | while (sta < str.size() && str[sta] != ',') ++sta; 92 | return sta; 93 | }; 94 | 95 | std::function findLetter = [](const std::string& str, unsigned int sta) 96 | { 97 | while (sta < str.size() && !isalpha(str[sta])) ++sta; 98 | return sta; 99 | }; 100 | 101 | std::function error = [](const std::string & func) 102 | { 103 | std::cerr << "Error: the number of parameters for " << func << " is not correct." << std::endl; 104 | exit(1); 105 | }; 106 | 107 | unsigned int pos = 0; 108 | 109 | while (pos < s.size()) 110 | { 111 | if (pos + 1 >= s.size()) 112 | { 113 | std::cerr << "Error: can't recognize the tree type abbreviation, it's too short.\n"; 114 | exit(1); 115 | } 116 | std::string type = s.substr(pos, 2); 117 | pos += 2; 118 | for_each(type.begin(), type.end(), [](char& x){x = tolower(x);}); 119 | int nextLetter = findLetter(s, pos); 120 | if (type == "lh") 121 | { 122 | int nextComma = findComma(s, pos); 123 | assert(nextComma < nextLetter); 124 | int n = atoi(s.substr(pos, nextComma - pos).c_str()); 125 | pos = nextComma + 1; 126 | nextComma = findComma(s, pos); 127 | assert(nextComma < nextLetter); 128 | double low, high; 129 | sscanf(s.substr(pos, nextComma - pos).c_str(), "%lf", &low); 130 | pos = nextComma + 1; 131 | nextComma = findComma(s, pos); 132 | assert(nextComma < nextLetter); 133 | sscanf(s.substr(pos, nextComma - pos).c_str(), "%lf", &high); 134 | pos = nextComma + 1; 135 | nextComma = findComma(s, pos); 136 | assert(nextComma >= nextLetter); 137 | int pa = atoi(s.substr(pos, nextComma - pos).c_str()); 138 | pos = nextLetter; 139 | lowhigh(n, low, high, pa); 140 | continue; 141 | } 142 | if (type == "lm") 143 | { 144 | int nextComma = findComma(s, pos); 145 | assert(nextComma < nextLetter); 146 | int n = atoi(s.substr(pos, nextComma - pos).c_str()); 147 | pos = nextComma + 1; 148 | nextComma = findComma(s, pos); 149 | assert(nextComma < nextLetter); 150 | int k = atoi(s.substr(pos, nextComma - pos).c_str()); 151 | pos = nextComma + 1; 152 | nextComma = findComma(s, pos); 153 | assert(nextComma < nextLetter); 154 | double low, high; 155 | sscanf(s.substr(pos, nextComma - pos).c_str(), "%lf", &low); 156 | pos = nextComma + 1; 157 | nextComma = findComma(s, pos); 158 | assert(nextComma < nextLetter); 159 | sscanf(s.substr(pos, nextComma - pos).c_str(), "%lf", &high); 160 | pos = nextComma + 1; 161 | nextComma = findComma(s, pos); 162 | assert(nextComma >= nextLetter); 163 | int pa = atoi(s.substr(pos, nextComma - pos).c_str()); 164 | pos = nextLetter; 165 | lowhighMaxDegree(n, k, low, high, pa); 166 | continue; 167 | } 168 | std::vector par; 169 | while (1) 170 | { 171 | int nextComma = findComma(s, pos); 172 | par.push_back(atoi(s.substr(pos, nextComma - pos).c_str())); 173 | pos = nextComma + 1; 174 | if (nextComma >= nextLetter) 175 | { 176 | pos = nextLetter; 177 | break; 178 | } 179 | } 180 | if (type == "nd") 181 | { 182 | if (par.size() == 1) addNode(par[0]); 183 | else error("addNode"); 184 | } 185 | else if (type == "rd") 186 | { 187 | if (par.size() == 2) random(par[0], par[1]); 188 | else error("random"); 189 | } 190 | else if (type == "tl") 191 | { 192 | if (par.size() == 3) tall(par[0], par[1], par[2]); 193 | else error("tall"); 194 | } 195 | else if (type == "ch") 196 | { 197 | if (par.size() == 2) chain(par[0], par[1]); 198 | else error("chain"); 199 | } 200 | else if (type == "st") 201 | { 202 | if (par.size() == 2) star(par[0], par[1]); 203 | else error("star"); 204 | } 205 | else if (type == "fl") 206 | { 207 | if (par.size() == 2) flower(par[0], par[1]); 208 | else error("flower"); 209 | } 210 | else if (type == "md") 211 | { 212 | if (par.size() == 3) maxDegree(par[0], par[1], par[2]); 213 | else error("maxDegree"); 214 | } 215 | else if (type == "cp") 216 | { 217 | if (par.size() == 3) complete(par[0], par[1], par[2]); 218 | else error("complete"); 219 | } 220 | else if (type == "bi") 221 | { 222 | if (par.size() == 2) binary(par[0], par[1]); 223 | else error("binary"); 224 | } 225 | else if (type == "cb") 226 | { 227 | if (par.size() == 2) completeBinary(par[0], par[1]); 228 | else error("completeBinary"); 229 | } 230 | else if (type == "sw") 231 | { 232 | if (par.size() == 2) silkworm(par[0], par[1]); 233 | else error("silkworm"); 234 | } 235 | else if (type == "al") 236 | { 237 | if (par.size() == 3) addLeaves(par[0], par[1], par[2]); 238 | else error("addLeaves"); 239 | } 240 | else 241 | { 242 | std::cerr << "Error: can't recognize the tree type abbreviation " << type << "." << std::endl; 243 | exit(1); 244 | } 245 | } 246 | } 247 | int size() const { return id.size(); } 248 | void addNode(int pa) 249 | { 250 | assert(pa >= 0); 251 | assert(pa < size()); 252 | id.push_back(id.size()); 253 | p.push_back(pa); 254 | eid.push_back(id.size() - 1); 255 | } 256 | void random(int n, int pa) 257 | { 258 | int sz = size(); 259 | assert(n > 0); 260 | assert(pa >= 0); 261 | assert(pa < sz); 262 | addNode(pa); 263 | if (n == 1) return; 264 | if (n == 2) 265 | { 266 | addNode(sz); 267 | return; 268 | } 269 | std::vector prufer, cnt; 270 | std::vector > g; 271 | g.resize(n); 272 | cnt.resize(n, 0); 273 | for (int i = 0; i < n - 2; ++i) 274 | { 275 | int x = randint(0, n - 1); 276 | prufer.push_back(x); 277 | ++cnt[x]; 278 | } 279 | std::priority_queue q; 280 | for (int i = 0; i < n; ++i) if (!cnt[i]) q.push(i); 281 | for (auto v : prufer) 282 | { 283 | int u = q.top(); 284 | g[u].push_back(v); 285 | g[v].push_back(u); 286 | q.pop(); 287 | if (--cnt[v] == 0) q.push(v); 288 | } 289 | int x = q.top(); 290 | q.pop(); 291 | int y = q.top(); 292 | g[x].push_back(y); 293 | g[y].push_back(x); 294 | 295 | std::queue bfs; 296 | 297 | bfs.push(0); 298 | int _id = sz; 299 | 300 | while (!bfs.empty()) 301 | { 302 | int u = bfs.front(); 303 | cnt[u] = 1; 304 | bfs.pop(); 305 | for (auto v : g[u]) 306 | { 307 | if (cnt[v] == 0) 308 | { 309 | addNode(_id); 310 | bfs.push(v); 311 | } 312 | } 313 | ++_id; 314 | } 315 | } 316 | void lowhigh(int n, double low, double high, int pa) 317 | { 318 | int sz = size(); 319 | assert(n > 0); 320 | assert(low >= 0); 321 | assert(high <= 1); 322 | assert(high >= low); 323 | assert(pa >= 0); 324 | assert(pa < sz); 325 | addNode(pa); 326 | for (int i = 1; i < n; ++i) addNode(randint(round((i - 1) * low), round((i - 1) * high)) + sz); 327 | } 328 | void tall(int n, int k, int pa) 329 | { 330 | int sz = size(); 331 | assert(n > 0); 332 | assert(k > 0); 333 | assert(pa >= 0); 334 | assert(pa < sz); 335 | addNode(pa); 336 | for (int i = sz + 1; i < sz + n; ++i) addNode(randint(std::max(sz, i - k), i - 1)); 337 | } 338 | void chain(int n, int pa) 339 | { 340 | assert(n > 0); 341 | assert(pa >= 0); 342 | assert(pa < size()); 343 | tall(n, 1, pa); 344 | } 345 | void star(int n, int pa) 346 | { 347 | int sz = size(); 348 | assert(n > 0); 349 | assert(pa >= 0); 350 | assert(pa < sz); 351 | addNode(pa); 352 | for (int i = sz + 1; i < sz + n; ++i) addNode(sz); 353 | } 354 | void flower(int n, int pa) 355 | { 356 | assert(n > 0); 357 | assert(pa >= 0); 358 | assert(pa < size()); 359 | star(n, pa); 360 | } 361 | void maxDegree(int n, int k, int pa) 362 | { 363 | int sz = size(); 364 | assert(n > 0); 365 | assert(k >= 2); 366 | assert(pa >= 0); 367 | assert(pa < sz); 368 | addNode(pa); 369 | __gnu_pbds::tree, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update> remain; 370 | remain.insert(pii(sz, k - 1)); 371 | for (int i = sz + 1; i < sz + n; ++i) 372 | { 373 | auto it = remain.find_by_order(randint(0, remain.size() - 1)); 374 | int u = it->first; 375 | int t = it->second; 376 | remain.erase(it); 377 | if (t > 1) remain.insert(pii(u, t - 1)); 378 | addNode(u); 379 | remain.insert(pii(i, k - 1)); 380 | } 381 | } 382 | void lowhighMaxDegree(int n, int k, double low, double high, int pa) 383 | { 384 | int sz = size(); 385 | assert(n > 0); 386 | assert(k >= 2); 387 | assert(low >= 0); 388 | assert(high <= 1); 389 | assert(pa >= 0); 390 | assert(pa < sz); 391 | addNode(pa); 392 | __gnu_pbds::tree, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update> remain; 393 | remain.insert(pii(sz, k - 1)); 394 | for (int i = sz + 1; i < sz + n; ++i) 395 | { 396 | auto it = remain.find_by_order(randint(round((remain.size() - 1) * low), round((remain.size() - 1) * high))); 397 | int u = it->first; 398 | int t = it->second; 399 | remain.erase(it); 400 | if (t > 1) remain.insert(pii(u, t - 1)); 401 | addNode(u); 402 | remain.insert(pii(i, k - 1)); 403 | } 404 | } 405 | void complete(int n, int k, int pa) 406 | { 407 | int sz = size(); 408 | assert(n > 0); 409 | assert(k >= 2); 410 | assert(pa >= 0); 411 | assert(pa < sz); 412 | addNode(pa); 413 | for (int i = sz + 1; i < sz + n; ++i) addNode(sz + ceil(1.0 * (i - sz) / (k - 1) - 1e-9) - 1); 414 | } 415 | void binary(int n, int pa) 416 | { 417 | assert(n > 0); 418 | assert(pa >= 0); 419 | assert(pa < size()); 420 | maxDegree(n, 3, pa); 421 | } 422 | void completeBinary(int n, int pa) 423 | { 424 | assert(n > 0); 425 | assert(pa >= 0); 426 | assert(pa < size()); 427 | complete(n, 3, pa); 428 | } 429 | void silkworm(int n, int pa) 430 | { 431 | int sz = size(); 432 | assert(n > 0); 433 | assert(pa >= 0); 434 | assert(pa < sz); 435 | int chain_len = (n + 1) / 2; 436 | chain(chain_len, pa); 437 | for (int i = sz; i + chain_len < sz + n; ++i) addNode(i); 438 | } 439 | void addLeaves(int n, int l, int r) 440 | { 441 | assert(n > 0); 442 | assert(l >= 0); 443 | assert(r < size()); 444 | assert(l <= r); 445 | for (int i = 1; i <= n; ++i) addNode(randint(l, r)); 446 | } 447 | void shuffleNodes(int from = 0) 448 | { 449 | for (int i = 0; i < from; ++i) id[i] = i; 450 | for (unsigned int i = from; i < id.size(); ++i) 451 | { 452 | id[i] = i; 453 | std::swap(id[i], id[randint(from, i)]); 454 | } 455 | } 456 | void shuffleEdges() 457 | { 458 | for (unsigned int i = 0; i < eid.size(); ++i) 459 | { 460 | eid[i] = i + 1; 461 | std::swap(eid[i], eid[randint(0, i)]); 462 | } 463 | } 464 | void resize(int n) 465 | { 466 | assert(n > 0); 467 | if (size() < n) addLeaves(n - size(), 0, size() - 1); 468 | else if (size() > n) 469 | { 470 | p.resize(n); 471 | id.resize(n); 472 | eid.resize(n - 1); 473 | for (int i = 0; i < n; ++i) id[i] = i; 474 | for (int i = 0; i < n - 1; ++i) eid[i] = i + 1; 475 | } 476 | } 477 | void printEdge(int edgeID, std::ostream& os = std::cout) const 478 | { 479 | outputEdge(os, id[eid[edgeID]], id[p[eid[edgeID]]]); 480 | } 481 | int parent(int u) const 482 | { 483 | return p[u]; 484 | } 485 | friend std::ostream& operator<<(std::ostream& os, const Tree& t) 486 | { 487 | for (unsigned int i = 0; i < t.eid.size(); ++i) t.printEdge(i, os); 488 | return os; 489 | } 490 | }; 491 | } 492 | 493 | #endif 494 | --------------------------------------------------------------------------------