├── checker ├── linux │ ├── lcmp │ ├── wcmp │ ├── rcmp4 │ ├── rcmp6 │ ├── rcmp9 │ └── yesno ├── macos │ ├── lcmp │ ├── wcmp │ ├── rcmp4 │ ├── rcmp6 │ ├── rcmp9 │ └── yesno ├── windows │ ├── lcmp.exe │ ├── rcmp4.exe │ ├── rcmp6.exe │ ├── rcmp9.exe │ ├── wcmp.exe │ └── yesno.exe ├── rcmp4.cpp ├── rcmp6.cpp ├── rcmp9.cpp ├── wcmp.cpp ├── lcmp.cpp └── yesno.cpp ├── src ├── basic │ ├── checker │ │ ├── linux │ │ │ ├── lcmp │ │ │ ├── wcmp │ │ │ ├── rcmp4 │ │ │ ├── rcmp6 │ │ │ ├── rcmp9 │ │ │ └── yesno │ │ ├── windows │ │ │ ├── lcmp.exe │ │ │ ├── rcmp4.exe │ │ │ ├── rcmp6.exe │ │ │ ├── rcmp9.exe │ │ │ ├── wcmp.exe │ │ │ └── yesno.exe │ │ ├── rcmp4.cpp │ │ ├── rcmp6.cpp │ │ ├── rcmp9.cpp │ │ ├── wcmp.cpp │ │ ├── lcmp.cpp │ │ └── yesno.cpp │ ├── common.h │ ├── gen_strategy.h │ ├── tools.h │ ├── setting.h │ ├── enum.h │ └── macro.h ├── graph │ ├── link_forward.h │ ├── weight_type.h │ ├── node.h │ ├── all_tree_graph.h │ ├── unweight.h │ ├── edge.h │ ├── graph.h │ ├── chain.h │ ├── gen_function.h │ ├── flower.h │ ├── cycle_graph.h │ ├── wheel_graph.h │ ├── height_tree.h │ ├── tree.h │ ├── edge_weight.h │ ├── node_weight.h │ ├── max_degree_tree.h │ ├── dag.h │ └── max_son_tree.h ├── rand │ └── number_const.h ├── geometry │ ├── triangle.h │ ├── geometry_basic.h │ ├── geometry_algorithm.h │ ├── simple_polygon.h │ ├── geometry_strategy.h │ ├── line_segment.h │ ├── range_format.h │ ├── point.h │ ├── points.h │ └── coordinate.h ├── io │ ├── command_path.h │ ├── validate.h │ ├── command_func.h │ ├── io_reporter.h │ └── inputs_outputs.h └── log │ └── color.h ├── .gitignore ├── test ├── test.cpp ├── validate │ ├── val.cpp │ └── test.cpp ├── test_basic.hpp ├── test_tools.hpp ├── algorithm │ ├── geometry_checker.h │ ├── cactus_checker.h │ ├── Prufer.h │ ├── Manacher.h │ ├── TopologicalSort.h │ ├── Bipartite.h │ ├── DSU.h │ └── VectorTree.h ├── test_geometry.hpp ├── test_array.hpp └── test_numeric.hpp ├── .github └── workflows │ ├── check_amalgamate.yml │ ├── test.yml │ └── amalgamate_debug.yml ├── LICENSE ├── README.md └── xmake.lua /checker/linux/lcmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/checker/linux/lcmp -------------------------------------------------------------------------------- /checker/linux/wcmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/checker/linux/wcmp -------------------------------------------------------------------------------- /checker/macos/lcmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/checker/macos/lcmp -------------------------------------------------------------------------------- /checker/macos/wcmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/checker/macos/wcmp -------------------------------------------------------------------------------- /checker/linux/rcmp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/checker/linux/rcmp4 -------------------------------------------------------------------------------- /checker/linux/rcmp6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/checker/linux/rcmp6 -------------------------------------------------------------------------------- /checker/linux/rcmp9: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/checker/linux/rcmp9 -------------------------------------------------------------------------------- /checker/linux/yesno: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/checker/linux/yesno -------------------------------------------------------------------------------- /checker/macos/rcmp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/checker/macos/rcmp4 -------------------------------------------------------------------------------- /checker/macos/rcmp6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/checker/macos/rcmp6 -------------------------------------------------------------------------------- /checker/macos/rcmp9: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/checker/macos/rcmp9 -------------------------------------------------------------------------------- /checker/macos/yesno: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/checker/macos/yesno -------------------------------------------------------------------------------- /checker/windows/lcmp.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/checker/windows/lcmp.exe -------------------------------------------------------------------------------- /checker/windows/rcmp4.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/checker/windows/rcmp4.exe -------------------------------------------------------------------------------- /checker/windows/rcmp6.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/checker/windows/rcmp6.exe -------------------------------------------------------------------------------- /checker/windows/rcmp9.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/checker/windows/rcmp9.exe -------------------------------------------------------------------------------- /checker/windows/wcmp.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/checker/windows/wcmp.exe -------------------------------------------------------------------------------- /checker/windows/yesno.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/checker/windows/yesno.exe -------------------------------------------------------------------------------- /src/basic/checker/linux/lcmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/src/basic/checker/linux/lcmp -------------------------------------------------------------------------------- /src/basic/checker/linux/wcmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/src/basic/checker/linux/wcmp -------------------------------------------------------------------------------- /src/basic/checker/linux/rcmp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/src/basic/checker/linux/rcmp4 -------------------------------------------------------------------------------- /src/basic/checker/linux/rcmp6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/src/basic/checker/linux/rcmp6 -------------------------------------------------------------------------------- /src/basic/checker/linux/rcmp9: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/src/basic/checker/linux/rcmp9 -------------------------------------------------------------------------------- /src/basic/checker/linux/yesno: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/src/basic/checker/linux/yesno -------------------------------------------------------------------------------- /src/basic/checker/windows/lcmp.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/src/basic/checker/windows/lcmp.exe -------------------------------------------------------------------------------- /src/basic/checker/windows/rcmp4.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/src/basic/checker/windows/rcmp4.exe -------------------------------------------------------------------------------- /src/basic/checker/windows/rcmp6.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/src/basic/checker/windows/rcmp6.exe -------------------------------------------------------------------------------- /src/basic/checker/windows/rcmp9.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/src/basic/checker/windows/rcmp9.exe -------------------------------------------------------------------------------- /src/basic/checker/windows/wcmp.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/src/basic/checker/windows/wcmp.exe -------------------------------------------------------------------------------- /src/basic/checker/windows/yesno.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuTian-SCPC/ACM-generator/HEAD/src/basic/checker/windows/yesno.exe -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .idea/ 3 | debug/ 4 | # Xmake cache 5 | .xmake/ 6 | build/ 7 | src/testlib.h 8 | src/basic/testlib.h 9 | 10 | # MacOS Cache 11 | .DS_Store -------------------------------------------------------------------------------- /test/test.cpp: -------------------------------------------------------------------------------- 1 | #include "test_tools.hpp" 2 | #include "test_numeric.hpp" 3 | #include "test_array.hpp" 4 | #include "test_tree.hpp" 5 | #include "test_graph.hpp" 6 | #include "test_geometry.hpp" 7 | -------------------------------------------------------------------------------- /.github/workflows/check_amalgamate.yml: -------------------------------------------------------------------------------- 1 | name: Check Amalgamate 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | call-check-header: 7 | uses: ./.github/workflows/amalgamate_debug.yml 8 | with: 9 | file: generator.h 10 | command: xmake merge -------------------------------------------------------------------------------- /test/validate/val.cpp: -------------------------------------------------------------------------------- 1 | #include "../../testlib.h" 2 | int main(int argc, char* argv[]) { 3 | registerValidation(argc, argv); 4 | 5 | inf.readInt(1, 1000000); 6 | inf.readSpace(); 7 | inf.readInt(1, 1000000); 8 | inf.readEoln(); 9 | 10 | inf.readEof(); 11 | return 0; 12 | } -------------------------------------------------------------------------------- /test/test_basic.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../generator.h" 4 | #include "catch_amalgamated.hpp" 5 | using namespace generator::all; 6 | 7 | inline bool loop_check(std::function func, int times) { 8 | for (int i = 0; i < times; i++) if (!func()) return false; 9 | return true; 10 | } 11 | 12 | inline int int_weight() { return rand_int(1, 100); } 13 | 14 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | test: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v2 18 | 19 | - name: Set up Xmake 20 | run: | 21 | wget https://xmake.io/shget.text -O - | bash 22 | export PATH=$HOME/.xmake/bin:$PATH 23 | 24 | - name: Run Xmake tests 25 | run: | 26 | xmake f -y 27 | xmake run_test -------------------------------------------------------------------------------- /test/test_tools.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "test_basic.hpp" 3 | using namespace generator::all; 4 | 5 | TEST_CASE("string format", "[tools][format]") { 6 | init_gen(); 7 | std::string s = string_format("%d %c %s", 1, 'a', "abc"); 8 | CHECK(s == "1 a abc"); 9 | } 10 | 11 | TEST_CASE("string join", "[tools][format]") { 12 | init_gen(); 13 | std::string s = string_join("/", 'a', "abc", 123); 14 | CHECK(s == "a/abc/123"); 15 | std::string s2 = string_join("@", s, 1, "a"); 16 | CHECK(s == "a/abc/123"); 17 | CHECK(s2 == "a/abc/123@1@a"); 18 | } -------------------------------------------------------------------------------- /src/graph/link_forward.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_LINK_FORWARD_H_ 2 | #define _SGPCET_LINK_FORWARD_H_ 3 | 4 | #ifndef _SGPCET_COMMON_H_ 5 | #include "basic/common.h" 6 | #endif // !_SGPCET_COMMON_H_ 7 | 8 | namespace generator { 9 | namespace rand_graph { 10 | namespace basic { 11 | template 12 | class _LinkImpl; 13 | 14 | template 15 | class _TreeLinkImpl; 16 | 17 | } // namespace basic 18 | } // namespace rand_graph 19 | } // namespace generator 20 | 21 | #endif // !_SGPCET_LINK_FORWARD_H_ 22 | -------------------------------------------------------------------------------- /src/basic/common.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_COMMON_H_ 2 | #define _SGPCET_COMMON_H_ 3 | 4 | #include"testlib.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #ifdef ON_WINDOWS 15 | #include 16 | #include 17 | #include 18 | #define dup _dup 19 | #define dup2 _dup2 20 | #define fileno _fileno 21 | #define mkdir(dir, mode) _mkdir(dir) 22 | #define stat _stat 23 | #else 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #endif 31 | 32 | #ifdef __APPLE__ 33 | #include 34 | #endif 35 | 36 | #endif // !_SGPCET_COMMON_H_ 37 | -------------------------------------------------------------------------------- /checker/rcmp4.cpp: -------------------------------------------------------------------------------- 1 | #include "testlib.h" 2 | 3 | using namespace std; 4 | 5 | const double EPS = 1E-4; 6 | 7 | int main(int argc, char *argv[]) { 8 | setName("compare two sequences of doubles, max absolute or relative error = %.5f", EPS); 9 | registerTestlibCmd(argc, argv); 10 | 11 | int n = 0; 12 | double j = 0, p = 0; 13 | 14 | while (!ans.seekEof()) { 15 | n++; 16 | j = ans.readDouble(); 17 | p = ouf.readDouble(); 18 | if (!doubleCompare(j, p, EPS)) { 19 | quitf(_wa, "%d%s numbers differ - expected: '%.5f', found: '%.5f', error = '%.5f'", 20 | n, englishEnding(n).c_str(), j, p, doubleDelta(j, p)); 21 | } 22 | } 23 | 24 | if (n == 1) 25 | quitf(_ok, "found '%.5f', expected '%.5f', error '%.5f'", p, j, doubleDelta(j, p)); 26 | 27 | quitf(_ok, "%d numbers", n); 28 | } 29 | -------------------------------------------------------------------------------- /checker/rcmp6.cpp: -------------------------------------------------------------------------------- 1 | #include "testlib.h" 2 | 3 | using namespace std; 4 | 5 | const double EPS = 1E-6; 6 | 7 | int main(int argc, char *argv[]) { 8 | setName("compare two sequences of doubles, max absolute or relative error = %.7f", EPS); 9 | registerTestlibCmd(argc, argv); 10 | 11 | int n = 0; 12 | double j = 0, p = 0; 13 | 14 | while (!ans.seekEof()) { 15 | n++; 16 | j = ans.readDouble(); 17 | p = ouf.readDouble(); 18 | if (!doubleCompare(j, p, EPS)) { 19 | quitf(_wa, "%d%s numbers differ - expected: '%.7f', found: '%.7f', error = '%.7f'", 20 | n, englishEnding(n).c_str(), j, p, doubleDelta(j, p)); 21 | } 22 | } 23 | 24 | if (n == 1) 25 | quitf(_ok, "found '%.7f', expected '%.7f', error '%.7f'", p, j, doubleDelta(j, p)); 26 | 27 | quitf(_ok, "%d numbers", n); 28 | } 29 | -------------------------------------------------------------------------------- /checker/rcmp9.cpp: -------------------------------------------------------------------------------- 1 | #include "testlib.h" 2 | 3 | using namespace std; 4 | 5 | const double EPS = 1E-9; 6 | 7 | int main(int argc, char *argv[]) { 8 | setName("compare two sequences of doubles, max absolute or relative error = %.10f", EPS); 9 | registerTestlibCmd(argc, argv); 10 | 11 | int n = 0; 12 | double j = 0, p = 0; 13 | 14 | while (!ans.seekEof()) { 15 | n++; 16 | j = ans.readDouble(); 17 | p = ouf.readDouble(); 18 | if (!doubleCompare(j, p, EPS)) { 19 | quitf(_wa, "%d%s numbers differ - expected: '%.10f', found: '%.10f', error = '%.10f'", 20 | n, englishEnding(n).c_str(), j, p, doubleDelta(j, p)); 21 | } 22 | } 23 | 24 | if (n == 1) 25 | quitf(_ok, "found '%.10f', expected '%.10f', error '%.10f'", p, j, doubleDelta(j, p)); 26 | 27 | quitf(_ok, "%d numbers", n); 28 | } 29 | -------------------------------------------------------------------------------- /src/basic/checker/rcmp4.cpp: -------------------------------------------------------------------------------- 1 | #include "testlib.h" 2 | 3 | using namespace std; 4 | 5 | const double EPS = 1E-4; 6 | 7 | int main(int argc, char *argv[]) { 8 | setName("compare two sequences of doubles, max absolute or relative error = %.5f", EPS); 9 | registerTestlibCmd(argc, argv); 10 | 11 | int n = 0; 12 | double j = 0, p = 0; 13 | 14 | while (!ans.seekEof()) { 15 | n++; 16 | j = ans.readDouble(); 17 | p = ouf.readDouble(); 18 | if (!doubleCompare(j, p, EPS)) { 19 | quitf(_wa, "%d%s numbers differ - expected: '%.5f', found: '%.5f', error = '%.5f'", 20 | n, englishEnding(n).c_str(), j, p, doubleDelta(j, p)); 21 | } 22 | } 23 | 24 | if (n == 1) 25 | quitf(_ok, "found '%.5f', expected '%.5f', error '%.5f'", p, j, doubleDelta(j, p)); 26 | 27 | quitf(_ok, "%d numbers", n); 28 | } 29 | -------------------------------------------------------------------------------- /src/basic/checker/rcmp6.cpp: -------------------------------------------------------------------------------- 1 | #include "testlib.h" 2 | 3 | using namespace std; 4 | 5 | const double EPS = 1E-6; 6 | 7 | int main(int argc, char *argv[]) { 8 | setName("compare two sequences of doubles, max absolute or relative error = %.7f", EPS); 9 | registerTestlibCmd(argc, argv); 10 | 11 | int n = 0; 12 | double j = 0, p = 0; 13 | 14 | while (!ans.seekEof()) { 15 | n++; 16 | j = ans.readDouble(); 17 | p = ouf.readDouble(); 18 | if (!doubleCompare(j, p, EPS)) { 19 | quitf(_wa, "%d%s numbers differ - expected: '%.7f', found: '%.7f', error = '%.7f'", 20 | n, englishEnding(n).c_str(), j, p, doubleDelta(j, p)); 21 | } 22 | } 23 | 24 | if (n == 1) 25 | quitf(_ok, "found '%.7f', expected '%.7f', error '%.7f'", p, j, doubleDelta(j, p)); 26 | 27 | quitf(_ok, "%d numbers", n); 28 | } 29 | -------------------------------------------------------------------------------- /src/basic/checker/rcmp9.cpp: -------------------------------------------------------------------------------- 1 | #include "testlib.h" 2 | 3 | using namespace std; 4 | 5 | const double EPS = 1E-9; 6 | 7 | int main(int argc, char *argv[]) { 8 | setName("compare two sequences of doubles, max absolute or relative error = %.10f", EPS); 9 | registerTestlibCmd(argc, argv); 10 | 11 | int n = 0; 12 | double j = 0, p = 0; 13 | 14 | while (!ans.seekEof()) { 15 | n++; 16 | j = ans.readDouble(); 17 | p = ouf.readDouble(); 18 | if (!doubleCompare(j, p, EPS)) { 19 | quitf(_wa, "%d%s numbers differ - expected: '%.10f', found: '%.10f', error = '%.10f'", 20 | n, englishEnding(n).c_str(), j, p, doubleDelta(j, p)); 21 | } 22 | } 23 | 24 | if (n == 1) 25 | quitf(_ok, "found '%.10f', expected '%.10f', error '%.10f'", p, j, doubleDelta(j, p)); 26 | 27 | quitf(_ok, "%d numbers", n); 28 | } 29 | -------------------------------------------------------------------------------- /test/validate/test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../generator.h" 2 | #include "catch_amalgamated.hpp" 3 | using namespace generator::all; 4 | 5 | TEST_CASE("validate for linux", "[validate][linux]") { 6 | init_gen(); 7 | make_inputs(1, 3, [&]() { 8 | println(rand_int(1, 10), rand_int(1, 10), 2, "abc"); 9 | }); 10 | make_inputs(4, 5, [&]() { 11 | println(rand_even(1, 1000000), rand_even(1, 1000000)); 12 | }); 13 | Path folder = __validate_folder("testcases"); 14 | __create_directories(folder); 15 | CommandPath val(__path_join(__current_path(), "val")); 16 | for (int i = 1; i <= 5; i++) { 17 | Path log = __path_join(folder, __end_with(i, _VAL)); 18 | Path input = __input_file_path(__path_join(__current_path(), "testcases"), i); 19 | ReturnState state = __run_program(val, input, _default_path, log, time_limit_inf, _VALIDATOR); 20 | if (i <= 3) CHECK(!__is_success(state.exit_code)); 21 | else CHECK(__is_success(state.exit_code)); 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /checker/wcmp.cpp: -------------------------------------------------------------------------------- 1 | #include "testlib.h" 2 | 3 | using namespace std; 4 | 5 | int main(int argc, char *argv[]) { 6 | setName("compare sequences of tokens"); 7 | registerTestlibCmd(argc, argv); 8 | 9 | int n = 0; 10 | string j, p; 11 | 12 | while (!ans.seekEof() && !ouf.seekEof()) { 13 | n++; 14 | 15 | ans.readWordTo(j); 16 | ouf.readWordTo(p); 17 | 18 | if (j != p) 19 | quitf(_wa, "%d%s words differ - expected: '%s', found: '%s'", n, englishEnding(n).c_str(), 20 | compress(j).c_str(), compress(p).c_str()); 21 | } 22 | 23 | if (ans.seekEof() && ouf.seekEof()) { 24 | if (n == 1) 25 | quitf(_ok, "\"%s\"", compress(j).c_str()); 26 | else 27 | quitf(_ok, "%d tokens", n); 28 | } else { 29 | if (ans.seekEof()) 30 | quitf(_wa, "Participant output contains extra tokens"); 31 | else 32 | quitf(_wa, "Unexpected EOF in the participants output"); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/basic/checker/wcmp.cpp: -------------------------------------------------------------------------------- 1 | #include "testlib.h" 2 | 3 | using namespace std; 4 | 5 | int main(int argc, char *argv[]) { 6 | setName("compare sequences of tokens"); 7 | registerTestlibCmd(argc, argv); 8 | 9 | int n = 0; 10 | string j, p; 11 | 12 | while (!ans.seekEof() && !ouf.seekEof()) { 13 | n++; 14 | 15 | ans.readWordTo(j); 16 | ouf.readWordTo(p); 17 | 18 | if (j != p) 19 | quitf(_wa, "%d%s words differ - expected: '%s', found: '%s'", n, englishEnding(n).c_str(), 20 | compress(j).c_str(), compress(p).c_str()); 21 | } 22 | 23 | if (ans.seekEof() && ouf.seekEof()) { 24 | if (n == 1) 25 | quitf(_ok, "\"%s\"", compress(j).c_str()); 26 | else 27 | quitf(_ok, "%d tokens", n); 28 | } else { 29 | if (ans.seekEof()) 30 | quitf(_wa, "Participant output contains extra tokens"); 31 | else 32 | quitf(_wa, "Unexpected EOF in the participants output"); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 ChuTian-SCPC 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 | -------------------------------------------------------------------------------- /.github/workflows/amalgamate_debug.yml: -------------------------------------------------------------------------------- 1 | name: Check Header Consistency 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | file: 7 | required: true 8 | type: string 9 | command: 10 | default: xmake merge 11 | type: string 12 | 13 | jobs: 14 | check: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - name: Install Xmake 20 | run: bash <(curl -fsSL https://xmake.io/shget.text) 21 | 22 | - name: Generate Header 23 | run: ${{ inputs.command }} 24 | 25 | - name: Validate Consistency 26 | run: | 27 | sed 's/\r//' "${{ inputs.file }}" | sed '/^\/\/ Time: /d' > local_clean.h 28 | git show HEAD:${{ inputs.file }} | sed 's/\r//' | sed '/^\/\/ Time: /d' > head_clean.h 29 | 30 | if ! diff -u head_clean.h local_clean.h; then 31 | echo "::error::${{ inputs.file }} is not up to date. Please run '${{ inputs.command }}' and commit the result." 32 | exit 1 33 | fi 34 | 35 | - name: Upload diff context (on failure) 36 | if: failure() 37 | uses: actions/upload-artifact@v4 38 | with: 39 | name: header-diff 40 | path: | 41 | local_clean.h 42 | head_clean.h -------------------------------------------------------------------------------- /checker/lcmp.cpp: -------------------------------------------------------------------------------- 1 | #include "testlib.h" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | bool compareWords(const string& a, const string& b) { 9 | vector va, vb; 10 | stringstream sa; 11 | 12 | sa << a; 13 | string cur; 14 | while (sa >> cur) 15 | va.push_back(cur); 16 | 17 | stringstream sb; 18 | sb << b; 19 | while (sb >> cur) 20 | vb.push_back(cur); 21 | 22 | return (va == vb); 23 | } 24 | 25 | int main(int argc, char *argv[]) { 26 | setName("compare files as sequence of tokens in lines"); 27 | registerTestlibCmd(argc, argv); 28 | 29 | string strAnswer; 30 | 31 | int n = 0; 32 | while (!ans.eof()) { 33 | std::string j = ans.readString(); 34 | 35 | if (j.empty() && ans.eof()) 36 | break; 37 | 38 | string p = ouf.readString(); 39 | strAnswer = p; 40 | 41 | n++; 42 | 43 | if (!compareWords(j, p)) 44 | quitf(_wa, "%d%s lines differ - expected: '%s', found: '%s'", n, englishEnding(n).c_str(), 45 | compress(j).c_str(), compress(p).c_str()); 46 | } 47 | 48 | if (n == 1) 49 | quitf(_ok, "single line: '%s'", compress(strAnswer).c_str()); 50 | 51 | quitf(_ok, "%d lines", n); 52 | } 53 | -------------------------------------------------------------------------------- /src/basic/checker/lcmp.cpp: -------------------------------------------------------------------------------- 1 | #include "testlib.h" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | bool compareWords(const string& a, const string& b) { 9 | vector va, vb; 10 | stringstream sa; 11 | 12 | sa << a; 13 | string cur; 14 | while (sa >> cur) 15 | va.push_back(cur); 16 | 17 | stringstream sb; 18 | sb << b; 19 | while (sb >> cur) 20 | vb.push_back(cur); 21 | 22 | return (va == vb); 23 | } 24 | 25 | int main(int argc, char *argv[]) { 26 | setName("compare files as sequence of tokens in lines"); 27 | registerTestlibCmd(argc, argv); 28 | 29 | string strAnswer; 30 | 31 | int n = 0; 32 | while (!ans.eof()) { 33 | std::string j = ans.readString(); 34 | 35 | if (j.empty() && ans.eof()) 36 | break; 37 | 38 | string p = ouf.readString(); 39 | strAnswer = p; 40 | 41 | n++; 42 | 43 | if (!compareWords(j, p)) 44 | quitf(_wa, "%d%s lines differ - expected: '%s', found: '%s'", n, englishEnding(n).c_str(), 45 | compress(j).c_str(), compress(p).c_str()); 46 | } 47 | 48 | if (n == 1) 49 | quitf(_ok, "single line: '%s'", compress(strAnswer).c_str()); 50 | 51 | quitf(_ok, "%d lines", n); 52 | } 53 | -------------------------------------------------------------------------------- /src/basic/gen_strategy.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_GEN_STRATEGY_H_ 2 | #define _SGPCET_GEN_STRATEGY_H_ 3 | 4 | #ifndef _SGPCET_LOGGER_H_ 5 | #include "log/logger.h" 6 | #endif // !_SGPCET_LOGGER_H_ 7 | 8 | namespace generator { 9 | namespace tools { 10 | class _Gen { 11 | public: 12 | _Gen(){} 13 | virtual void generate() { 14 | _msg::__fail_msg(_msg::_defl, "unsupport generator."); 15 | }; 16 | }; 17 | 18 | template 19 | class _BasicGen : public _Gen { 20 | protected: 21 | T& _context; 22 | public: 23 | _BasicGen(T& context) : _context(context) {} 24 | }; 25 | 26 | class _GenSwitch { 27 | protected: 28 | _Gen* _generator; 29 | public: 30 | _GenSwitch() : _generator(nullptr) {} 31 | virtual ~_GenSwitch() { __delete_generator(); } 32 | 33 | _SET_GET_VALUE(_Gen*, generator); 34 | 35 | protected: 36 | void __delete_generator() { 37 | if (_generator) delete _generator; 38 | } 39 | }; 40 | } // namespace tools 41 | } // namespace generator 42 | 43 | #endif // !_SGPCET_GEN_STRATEGY_H_ 44 | -------------------------------------------------------------------------------- /src/basic/tools.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_TOOLS_H_ 2 | #define _SGPCET_TOOLS_H_ 3 | 4 | #ifndef _SGPCET_COMMON_H_ 5 | #include "common.h" 6 | #endif // !_SGPCET_COMMON_H_ 7 | 8 | namespace generator { 9 | namespace tools { 10 | template 11 | void __join_helper(std::ostringstream& oss, std::string, const T& data) { 12 | oss << data; 13 | } 14 | 15 | template 16 | void __join_helper(std::ostringstream& oss, std::string split, const T& data, const Args&... args) { 17 | oss << data; 18 | oss << split; 19 | __join_helper(oss, split, args...); 20 | } 21 | 22 | template 23 | std::string string_join(std::string split, const Args&... args) { 24 | std::ostringstream oss; 25 | __join_helper(oss, split, args...); 26 | return oss.str(); 27 | } 28 | 29 | template 30 | std::string string_join(char split, const Args&... args) { 31 | std::ostringstream oss; 32 | __join_helper(oss, std::string(1, split), args...); 33 | return oss.str(); 34 | } 35 | 36 | std::string string_format(const char* format, ...) { 37 | FMT_TO_RESULT(format, format, _format); 38 | return _format; 39 | } 40 | 41 | } // namespace tools 42 | } // namespace generator 43 | 44 | #endif // !_SGPCET_TOOLS_H_ 45 | -------------------------------------------------------------------------------- /src/graph/weight_type.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_WEIGHT_TYPE_H_ 2 | #define _SGPCET_WEIGHT_TYPE_H_ 3 | 4 | #ifndef _SGPCET_COMMON_H_ 5 | #include "basic/common.h" 6 | #endif // !_SGPCET_COMMON_H_ 7 | 8 | namespace generator { 9 | namespace rand_graph { 10 | namespace basic { 11 | template 12 | using _IsBothWeight = typename std::enable_if< 13 | !std::is_void::value && !std::is_void::value, int>::type; 14 | 15 | template 16 | using _IsEdgeWeight = typename std::enable_if< 17 | std::is_void::value && !std::is_void::value, int>::type; 18 | 19 | template 20 | using _IsNodeWeight = typename std::enable_if< 21 | !std::is_void::value && std::is_void::value, int>::type; 22 | 23 | template 24 | using _IsUnweight = typename std::enable_if< 25 | std::is_void::value && std::is_void::value, int>::type; 26 | 27 | template 28 | using _HasT = typename std::enable_if::value, int>::type; 29 | 30 | template 31 | using _NotHasT = typename std::enable_if::value, int>::type; 32 | 33 | } // namespace basic 34 | } // namespace rand_graph 35 | } // namespace generator 36 | 37 | #endif // !_SGPCET_WEIGHT_TYPE_H_ 38 | -------------------------------------------------------------------------------- /src/rand/number_const.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_NUMBER_CONST_H_ 2 | #define _SGPCET_NUMBER_CONST_H_ 3 | 4 | #ifndef _SGPCET_COMMON_H_ 5 | #include "basic/common.h" 6 | #endif // !_SGPCET_COMMON_H_ 7 | #ifndef _SGPCET_ENUM_H_ 8 | #include "basic/enum.h" 9 | #endif // !_SGPCET_ENUM_H_ 10 | 11 | namespace generator { 12 | namespace rand_numeric { 13 | const long long __LONG_LONG_MIN = std::numeric_limits::min(); 14 | const unsigned long long __UNSIGNED_LONG_LONG_MAX = std::numeric_limits::max(); 15 | const unsigned long long __UNSIGNED_LONG_LONG_MIN = std::numeric_limits::min(); 16 | const unsigned long long __CHECK_LONG_LONG_MAX = (unsigned long long)std::numeric_limits::max(); 17 | const unsigned long long __CHECK_ABS_LONG_LONG_MIN = __CHECK_LONG_LONG_MAX + 1ULL; 18 | const unsigned long long __CHECK_UNSIGNED_LONG_MAX = (unsigned long long)std::numeric_limits::max(); 19 | 20 | template 21 | struct IsNumeric { 22 | static constexpr bool value = std::is_integral::value || std::is_floating_point::value; 23 | }; 24 | 25 | const std::string _PATTERN[_enum::MaxCharType]={ 26 | "[a-z]", 27 | "[A-Z]", 28 | "[a-zA-Z]", 29 | "[0-9]", 30 | "[a-zA-Z0-9]", 31 | "[01]" 32 | }; 33 | } // namespace rand_numeric 34 | } // namespace generator 35 | 36 | #endif // !_SGPCET_NUMBER_CONST_H_ 37 | -------------------------------------------------------------------------------- /src/graph/node.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_NODE_H_ 2 | #define _SGPCET_NODE_H_ 3 | 4 | #ifndef _SGPCET_MACRO_H_ 5 | #include "basic/macro.h" 6 | #endif // !_SGPCET_MACRO_H_ 7 | 8 | namespace generator { 9 | namespace rand_graph { 10 | namespace basic { 11 | template 12 | class _Node { 13 | protected: 14 | using _Self = _Node; 15 | U _w; 16 | _OUTPUT_FUNCTION(_Self) 17 | public: 18 | _Node() : _w(U()) { 19 | _DEFAULT_OUTPUT 20 | } 21 | _Node(U w) : _w(w) { 22 | _DEFAULT_OUTPUT 23 | } 24 | 25 | _SET_GET_VALUE(U, w) 26 | 27 | void default_output(std::ostream& os) const { 28 | os << _w ; 29 | } 30 | 31 | _OUTPUT_FUNCTION_SETTING(_Self) 32 | }; 33 | 34 | template<> 35 | class _Node { 36 | protected: 37 | using _Self = _Node; 38 | _OUTPUT_FUNCTION(_Self) 39 | public: 40 | _Node(){ 41 | _DEFAULT_OUTPUT 42 | } 43 | 44 | void default_output(std::ostream& os) const { return; } 45 | 46 | _OUTPUT_FUNCTION_SETTING(_Self) 47 | }; 48 | } // namespace basic 49 | } // namespace rand_graph 50 | } // namespace generator 51 | 52 | #endif // !_SGPCET_NODE_H_ 53 | -------------------------------------------------------------------------------- /src/graph/all_tree_graph.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_ALL_TREE_GRAPH_H_ 2 | #define _SGPCET_ALL_TREE_GRAPH_H_ 3 | 4 | #ifndef _SGPCET_TREE_H_ 5 | #include "tree.h" 6 | #endif // !_SGPCET_TREE_H_ 7 | #ifndef _SGPCET_CHAIN_H_ 8 | #include "chain.h" 9 | #endif // !_SGPCET_CHAIN_H_ 10 | #ifndef _SGPCET_FLOWER_H_ 11 | #include "flower.h" 12 | #endif // !_SGPCET_FLOWER_H_ 13 | #ifndef _SGPCET_HEIGHT_TREE_H_ 14 | #include "height_tree.h" 15 | #endif // !_SGPCET_HEIGHT_TREE_H_ 16 | #ifndef _SGPCET_MAX_DEGREE_TREE_H_ 17 | #include "max_degree_tree.h" 18 | #endif // !_SGPCET_MAX_DEGREE_TREE_H_ 19 | #ifndef _SGPCET_MAX_SON_TREE_H_ 20 | #include "max_son_tree.h" 21 | #endif // !_SGPCET_MAX_SON_TREE_H_ 22 | #ifndef _SGPCET_GRAPH_H_ 23 | #include "graph.h" 24 | #endif // !_SGPCET_GRAPH_H_ 25 | #ifndef _SGPCET_BIPARTITE_GRAPH_H_ 26 | #include "bipartite_graph.h" 27 | #endif // !_SGPCET_BIPARTITE_GRAPH_H_ 28 | #ifndef _SGPCET_DAG_H_ 29 | #include "dag.h" 30 | #endif // !_SGPCET_DAG_H_ 31 | #ifndef _SGPCET_CYCLE_GRAPH_H_ 32 | #include "cycle_graph.h" 33 | #endif // !_SGPCET_CYCLE_GRAPH_H_ 34 | #ifndef _SGPCET_WHEEL_GRAPH_H_ 35 | #include "wheel_graph.h" 36 | #endif // !_SGPCET_WHEEL_GRAPH_H_ 37 | #ifndef _SGPCET_GRID_GRAPH_H_ 38 | #include "grid_graph.h" 39 | #endif // !_SGPCET_GRID_GRAPH_H_ 40 | #ifndef _SGPCET_PSEUDO_TREE_H_ 41 | #include "pseudo_tree.h" 42 | #endif // !_SGPCET_PSEUDO_TREE_H_ 43 | #ifndef _SGPCET_CACTUS_H_ 44 | #include "cactus.h" 45 | #endif // !_SGPCET_CACTUS_H_ 46 | #ifndef _SGPCET_LINK_H_ 47 | #include "link.h" 48 | #endif // !_SGPCET_LINK_H_ 49 | #ifndef _SGPCET_FOREST_H_ 50 | #include "forest.h" 51 | #endif // !_SGPCET_FOREST_H_ 52 | #ifndef _SGPCET_FLOWER_CHAIN_H_ 53 | #include "flower_chain.h" 54 | #endif // !_SGPCET_FLOWER_CHAIN_H_ 55 | 56 | #endif // !_SGPCET_ALL_TREE_GRAPH_H_ 57 | -------------------------------------------------------------------------------- /test/algorithm/geometry_checker.h: -------------------------------------------------------------------------------- 1 | #include "../generator.h" 2 | using namespace generator::all; 3 | 4 | template 5 | bool is_segment_intersect(const Point& A, const Point& B, const Point& C, const Point& D) { 6 | _ResultTypeT c1 = (B - A) ^ (C - A); 7 | _ResultTypeT c2 = (B - A) ^ (D - A); 8 | _ResultTypeT c3 = (D - C) ^ (A - C); 9 | _ResultTypeT c4 = (D - C) ^ (B - C); 10 | 11 | if ((c1 * c2 < 0) && (c3 * c4 < 0)) return true; 12 | return false; 13 | } 14 | 15 | template 16 | bool is_simple_polygon(const SimplePolygon& polygon) { 17 | auto points = polygon.points(); 18 | int n = points.size(); 19 | if (n < 3) return true; 20 | for (int i = 0; i < n; i++) { 21 | Point A = points[i]; 22 | Point B = points[(i + 1) % n]; 23 | for (int j = i + 1; j < n; j++) { 24 | Point C = points[j]; 25 | Point D = points[(j + 1) % n]; 26 | if (is_segment_intersect(A, B, C, D)) { 27 | return false; 28 | } 29 | } 30 | } 31 | return true; 32 | } 33 | 34 | template 35 | bool is_convex_hull(const ConvexHull& polygon) { 36 | auto points = polygon.points(); 37 | int n = points.size(); 38 | if (n < 3) return true; 39 | 40 | double p = 0; 41 | for (int i = 0; i < n; i++) { 42 | Point O = points[i]; 43 | Point A = points[(i + 1) % n]; 44 | Point B = points[(i + 2) % n]; 45 | if (O == A || A == B) return false; 46 | double c = (A - O) ^ (B - O); 47 | 48 | if (c == 0) continue; 49 | if (p == 0) { 50 | p = c; 51 | } else if (c * p < 0) { 52 | return false; 53 | } 54 | } 55 | return true; 56 | } -------------------------------------------------------------------------------- /src/geometry/triangle.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_TRIANGLE_H_ 2 | #define _SGPCET_TRIANGLE_H_ 3 | 4 | #ifndef _SGPCET_CONVEX_HULL_H_ 5 | #include "convex_hull.h" 6 | #endif //!_SGPCET_CONVEX_HULL_H_ 7 | 8 | namespace generator { 9 | namespace rand_geometry { 10 | template ::value>::type> 11 | class Triangle; 12 | 13 | template ::value>::type> 14 | class TriangleGen : public ConvexHullGen { 15 | public: 16 | using Context = Triangle; 17 | TriangleGen(Context& points) : ConvexHullGen(points) {} 18 | }; 19 | 20 | template 21 | class Triangle : public ConvexHull { 22 | public: 23 | using _Self = Triangle; 24 | _OUTPUT_FUNCTION(_Self); 25 | public: 26 | Triangle(T x_left_limit = 0, T x_right_limit = 0, T y_left_limit = 0, T y_right_limit = 0) : 27 | ConvexHull(3, x_left_limit, x_right_limit, y_left_limit, y_right_limit) 28 | { 29 | _GEOMETRY_DEFAULT 30 | this->_output_node_count = false; 31 | } 32 | 33 | void default_output(std::ostream& os) const { 34 | if (this->_output_node_count) { 35 | os << this->_node_count << "\n"; 36 | } 37 | os << this->_points[0] << " " << this->_points[1] << " " << this->_points[2]; 38 | } 39 | 40 | _DISABLE_NODE_COUNT 41 | _OUTPUT_FUNCTION_SETTING(_Self) 42 | protected: 43 | _DEFAULT_GEOMETRY_GEN_FUNC(Triangle) 44 | }; 45 | } // namespace rand_geometry 46 | } // namespace generator 47 | #endif //!_SGPCET_TRIANGLE_H_ 48 | -------------------------------------------------------------------------------- /test/algorithm/cactus_checker.h: -------------------------------------------------------------------------------- 1 | #include "../generator.h" 2 | using namespace generator::all; 3 | 4 | struct CactusChecker { 5 | int node_count; 6 | int edge_count; 7 | std::vector> edges; 8 | std::vector dfn, low; 9 | int time; 10 | bool cactus; 11 | 12 | CactusChecker(int n, int m) : node_count(n), edge_count(m) { 13 | init(); 14 | } 15 | 16 | void resize(int n, int m) { 17 | node_count = n; 18 | edge_count = m; 19 | init(); 20 | } 21 | 22 | template 23 | void add_edge(basic::_Edge e) { 24 | int u = e.u(); 25 | int v = e.v(); 26 | edges[u].emplace_back(v); 27 | edges[v].emplace_back(u); 28 | } 29 | 30 | 31 | void dfs(int u, int fa) { 32 | time++; 33 | dfn[u] = time; 34 | low[u] = time; 35 | int cnt = 0; 36 | for (auto& v : edges[u]) { 37 | if (v == fa) continue; 38 | if (!dfn[v]) { 39 | dfs(v, u); 40 | low[u] = std::min(low[u], low[v]); 41 | } 42 | else low[u] = std::min(low[u], dfn[v]); 43 | if (low[v] < dfn[u]) { 44 | cnt++; 45 | if (cnt == 2) { 46 | cactus = false; 47 | return; 48 | } 49 | } 50 | if (!cactus) return; 51 | } 52 | } 53 | 54 | bool is_cactus() { 55 | dfs(0, -1); 56 | for (auto& d : dfn) if (!d) return false; 57 | return cactus; 58 | } 59 | protected: 60 | 61 | void init() { 62 | edges.clear(); 63 | dfn.clear(); 64 | low.clear(); 65 | edges.resize(node_count); 66 | dfn.resize(node_count, 0); 67 | low.resize(edge_count, 0); 68 | time = 0; 69 | cactus = true; 70 | } 71 | }; -------------------------------------------------------------------------------- /src/geometry/geometry_basic.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_GEOMETRY_BASIC_H_ 2 | #define _SGPCET_GEOMETRY_BASIC_H_ 3 | 4 | #ifndef _SGPCET_COMMON_H_ 5 | #include "basic/common.h" 6 | #endif //!_SGPCET_COMMON_H_ 7 | #ifndef _SGPCET_LOGGER_H_ 8 | #include "log/logger.h" 9 | #endif // !_SGPCET_NODE_H_ 10 | 11 | namespace generator { 12 | namespace rand_geometry { 13 | #if defined(__SIZEOF_INT128__) && __SIZEOF_INT128__ == 16 14 | using MaxIntType = __int128; 15 | std::ostream& operator<<(std::ostream& os, __int128 value) { 16 | if (value < 0) { 17 | os << "-"; 18 | value = -value; 19 | } 20 | 21 | std::string str; 22 | while (value > 0) { 23 | str.insert(str.begin(), '0' + (value % 10)); 24 | value /= 10; 25 | } 26 | 27 | if (str.empty()) { 28 | str = "0"; 29 | } 30 | 31 | os << str; 32 | return os; 33 | } 34 | #else 35 | using MaxIntType = long long; 36 | #endif 37 | 38 | template 39 | struct is_signed_integral { 40 | static const bool value = std::is_integral::value && !std::is_unsigned::value; 41 | }; 42 | 43 | template 44 | struct is_point_type { 45 | static const bool value = is_signed_integral::value || std::is_floating_point::value; 46 | }; 47 | 48 | template 49 | struct _ResultType { 50 | using type = typename std::conditional< 51 | is_signed_integral::value, 52 | MaxIntType, 53 | double 54 | >::type; 55 | }; 56 | 57 | template 58 | using _ResultTypeT = typename _ResultType::type; 59 | } // namespace rand_geometry 60 | } // namespace generator 61 | 62 | #endif //!_SGPCET_GEOMETRY_BASIC_H_ 63 | -------------------------------------------------------------------------------- /src/geometry/geometry_algorithm.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_GEOMETRY_ALGORITHM_H_ 2 | #define _SGPCET_GEOMETRY_ALGORITHM_H_ 3 | 4 | #ifndef _SGPCET_POINT_H_ 5 | #include "point.h" 6 | #endif //!_SGPCET_POINT_H_ 7 | #ifndef _SGPCET_LINE_SEGMENT_H_ 8 | #include "line_segment.h" 9 | #endif //!_SGPCET_LINE_SEGMENT_H_ 10 | 11 | namespace generator { 12 | namespace rand_geometry { 13 | 14 | template 15 | typename std::enable_if::value, int>::type 16 | __quadrant(Point p) { 17 | return ((p.y() < 0) << 1) | ((p.x() < 0) ^ (p.y() < 0)); 18 | } 19 | 20 | template 21 | typename std::enable_if::value, void>::type 22 | __polar_angle_sort(std::vector>& points, Point o = Point()) { 23 | std::sort(points.begin(), points.end(), [&](Point a, Point b) { 24 | Point oa = a - o; 25 | Point ob = b - o; 26 | int quadrant_a = __quadrant(oa); 27 | int quadrant_b = __quadrant(ob); 28 | if (quadrant_a == quadrant_b) { 29 | _ResultTypeT cross = oa ^ ob; 30 | if (cross == 0) return a.x() < b.x(); 31 | return cross > 0; 32 | } 33 | return quadrant_a < quadrant_b; 34 | }); 35 | } 36 | 37 | template 38 | _enum::PointDirection point_direction(Point a, Point b, Point c) { 39 | b = b - a; 40 | c = c - a; 41 | _ResultTypeT cross = b ^ c; 42 | if (cross > 0) return _enum::COUNTER_CLOCKWISE; 43 | if (cross < 0) return _enum::CLOCKWISE; 44 | if (b * c < 0) return _enum::ONLINE_BACK; 45 | if (b * b < c * c) return _enum::ONLINE_FRONT; 46 | return _enum::ON_SEGMENT; 47 | } 48 | 49 | template 50 | _enum::PointDirection point_direction(Point a, Segment s) { 51 | return point_direction(a, s.start, s.end); 52 | } 53 | 54 | } // namespace rand_geometry 55 | } // namespace generator 56 | 57 | #endif // !_SGPCET_GEOMETRY_ALGORITHM_H_ 58 | -------------------------------------------------------------------------------- /src/basic/setting.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_SETTING_H_ 2 | #define _SGPCET_SETTING_H_ 3 | 4 | #ifndef _SGPCET_COMMON_H_ 5 | #include "common.h" 6 | #endif // !_SGPCET_COMMON_H_ 7 | 8 | namespace generator { 9 | namespace io { 10 | std::string __lib_path() { 11 | return __FILE__; 12 | } 13 | }; // namespace io 14 | 15 | namespace _setting { 16 | int vector_limit = 10000000; // 1e7 17 | int node_limit = 10000000; 18 | int edge_limit = 10000000; 19 | 20 | int time_limit_inf = -1; 21 | int test_case_limit = 1000; 22 | 23 | #ifdef ON_WINDOWS 24 | char _path_split = '\\'; 25 | char _other_split = '/'; 26 | #else 27 | char _path_split = '/'; 28 | char _other_split = '\\'; 29 | #endif // ON_WINDOWS 30 | 31 | const char* _default_path = ""; 32 | 33 | std::string _checker_folder = "checker"; 34 | #ifdef ON_WINDOWS 35 | std::string _sub_checker_folder = "windows"; 36 | #elif defined(__APPLE__) 37 | std::string _sub_checker_folder = "macos"; 38 | #else 39 | std::string _sub_checker_folder = "linux"; 40 | #endif // ON_WINDOWS 41 | 42 | std::string _lib_folder = io::__lib_path(); 43 | std::string testcase_folder = "testcases"; 44 | std::string compare_folder = "cmp"; 45 | std::string hack_folder = "hack"; 46 | std::string validate_folder = "validate"; 47 | 48 | std::string input_suffix = ".in"; 49 | std::string output_suffix = ".out"; 50 | 51 | int _function_count = 0; 52 | 53 | bool same_log_for_class = false; 54 | 55 | std::string _first_generator_argv = "generator"; 56 | std::string _first_checker_argv = "checker"; 57 | std::string _first_validator_argv = "validator"; 58 | 59 | double time_limit_over_ratio = 2; 60 | double time_limit_check_ratio = 2; 61 | 62 | const int _error_return = -1; 63 | 64 | bool default_seed = true; 65 | std::string default_stable_seed = ""; 66 | std::string default_hack_stable_seed = "hack"; 67 | 68 | int _rand_sum_sum_limit = 1000000; 69 | };// namespace _setting 70 | 71 | };// namespace generator 72 | 73 | #endif // !_SGPCET_SETTING_H_ 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

Generator

3 |
4 | 5 | [![version](https://img.shields.io/badge/version-v0.9.0_beta-blue)](https://github.com/ChuTian-SCPC/problem_tool) 6 | [![license](https://img.shields.io/badge/license-MIT-green)](https://github.com/ChuTian-SCPC/problem_tool/blob/main/LICENSE) 7 | 8 | 你是否希望在使用[Testlib](https://github.com/MikeMirzayanov/testlib)出题时: 9 | 10 | - 对于generator不需要写批处理脚本。 11 | 12 | - 测试数据强度,以及针对错解随机hack数据。 13 | 14 | - 能够方便地生成树,包括具有特殊性质的树(链、菊花图、指定高度的树、限制最大度数的树、限制最大儿子数的树、菊花带链)。 15 | 16 | - 能够方便地生成图,包括具有特殊性质的图(二分图、有向无环图、环图、轮图、网格图、基环树、仙人掌、森林)。 17 | 18 | - 能够方便地生成凸包、简单多边形。 19 | 20 | Generator是基于testlib.h库封装的一个出题辅助工具库。 21 | 22 | 它实现了以上的功能,并且提供了较高的扩展性。 23 | 24 | 能够简单方便地生成数据: 25 | 26 | ```cpp 27 | #include "generator.h" 28 | using namespace std; 29 | using namespace generator::all; 30 | 31 | void gen_code() { 32 | int n = rand_int("[1, 1e6]"); 33 | unweight::Tree tree(n); 34 | tree.gen(); // 生成一棵n个节点的树,树没有点权和边权,节点边号为1~n 35 | cout << tree << endl; 36 | } 37 | 38 | int main() { 39 | fill_inputs(5, gen_code); 40 | return 0; 41 | } 42 | ``` 43 | 44 | 方便地进行对拍: 45 | 46 | ```cpp 47 | #include "generator.h" 48 | using namespace std; 49 | using namespace generator::all; 50 | 51 | void gen_code() { 52 | cout << rand_int(1, 100) << " " << rand_int(1, 100) << endl; 53 | } 54 | 55 | void std_code() { 56 | int a, b; 57 | cin >> a >> b; 58 | cout << a + b << endl; 59 | } 60 | 61 | int main() { 62 | // 用gen_code生成测试样例,std_code生成正确答案,使用lcmp作为checker。 63 | // 对于wa_code时间限制是1000ms,在结果不正确时,将该样例添加到测试样例。 64 | hack(gen_code, std_code, "wa_code.exe", lcmp, 1000); 65 | return 0; 66 | } 67 | ``` 68 | 69 | 70 | ## 如何使用 71 | 72 | 需要支持C++11。 73 | 74 | 将`testlib.h`,`generator.h`,文件夹`checker`放入同一个目录下。放在**标准库位置**或**工作目录**均可。 75 | 76 | 详细的使用文档见:[使用文档](https://chutian-scpc.github.io/generator-docs)。 77 | 78 | ## 开源协议 79 | 80 | 代码遵循MIT协议,欢迎使用本项目!如果您觉得这个项目对您有帮助,请给我们一个⭐️Star支持,也可以向其他出题人推荐! 81 | 82 | ## 提问&贡献 83 | 84 | 如果您在使用中遇到bug,发现问题以及有需要加入的功能需求,可以提出[Issue](https://github.com/ChuTian-SCPC/ACM-generator/issues/new)或者[Discussion](https://github.com/ChuTian-SCPC/ACM-generator/discussions/new/choose)。 85 | 86 | 您也可以对仓库fork后修正其中的问题或实现需求,提交[PR](https://github.com/ChuTian-SCPC/ACM-generator/pulls)。 87 | 88 | 89 | -------------------------------------------------------------------------------- /checker/yesno.cpp: -------------------------------------------------------------------------------- 1 | #include "testlib.h" 2 | #include 3 | 4 | using namespace std; 5 | 6 | const string YES = "YES"; 7 | const string NO = "NO"; 8 | 9 | int main(int argc, char *argv[]) { 10 | setName("%s", ("multiple " + YES + "/" + NO + " (case insensitive)").c_str()); 11 | registerTestlibCmd(argc, argv); 12 | 13 | int index = 0, yesCount = 0, noCount = 0; 14 | string pa; 15 | while (!ans.seekEof() && !ouf.seekEof()) { 16 | index++; 17 | string ja = upperCase(ans.readToken()); 18 | pa = upperCase(ouf.readToken()); 19 | 20 | if (ja != YES && ja != NO) 21 | quitf(_fail, "%s or %s expected in answer, but %s found [%d%s token]", 22 | YES.c_str(), NO.c_str(), compress(ja).c_str(), index, englishEnding(index).c_str()); 23 | 24 | if (pa == YES) 25 | yesCount++; 26 | else if (pa == NO) 27 | noCount++; 28 | else 29 | quitf(_pe, "%s or %s expected, but %s found [%d%s token]", 30 | YES.c_str(), NO.c_str(), compress(pa).c_str(), index, englishEnding(index).c_str()); 31 | 32 | if (ja != pa) 33 | quitf(_wa, "expected %s, found %s [%d%s token]", 34 | compress(ja).c_str(), compress(pa).c_str(), index, englishEnding(index).c_str()); 35 | } 36 | 37 | int extraInAnsCount = 0; 38 | while (!ans.seekEof()) { 39 | ans.readToken(); 40 | extraInAnsCount++; 41 | } 42 | 43 | int extraInOufCount = 0; 44 | while (!ouf.seekEof()) { 45 | ouf.readToken(); 46 | extraInOufCount++; 47 | } 48 | 49 | if (extraInAnsCount > 0) 50 | quitf(_wa, "Answer contains longer sequence [length = %d], but output contains %d elements", 51 | index + extraInAnsCount, index); 52 | 53 | if (extraInOufCount > 0) 54 | quitf(_wa, "Output contains longer sequence [length = %d], but answer contains %d elements", 55 | index + extraInOufCount, index); 56 | 57 | if (index == 0) 58 | quitf(_ok, "Empty output"); 59 | else if (index == 1) 60 | quitf(_ok, "%s", pa.c_str()); 61 | else 62 | quitf(_ok, "%d token(s): yes count is %d, no count is %d", index, yesCount, noCount); 63 | 64 | quitf(_fail, "Impossible case"); 65 | } 66 | -------------------------------------------------------------------------------- /src/basic/checker/yesno.cpp: -------------------------------------------------------------------------------- 1 | #include "testlib.h" 2 | #include 3 | 4 | using namespace std; 5 | 6 | const string YES = "YES"; 7 | const string NO = "NO"; 8 | 9 | int main(int argc, char *argv[]) { 10 | setName("%s", ("multiple " + YES + "/" + NO + " (case insensitive)").c_str()); 11 | registerTestlibCmd(argc, argv); 12 | 13 | int index = 0, yesCount = 0, noCount = 0; 14 | string pa; 15 | while (!ans.seekEof() && !ouf.seekEof()) { 16 | index++; 17 | string ja = upperCase(ans.readToken()); 18 | pa = upperCase(ouf.readToken()); 19 | 20 | if (ja != YES && ja != NO) 21 | quitf(_fail, "%s or %s expected in answer, but %s found [%d%s token]", 22 | YES.c_str(), NO.c_str(), compress(ja).c_str(), index, englishEnding(index).c_str()); 23 | 24 | if (pa == YES) 25 | yesCount++; 26 | else if (pa == NO) 27 | noCount++; 28 | else 29 | quitf(_pe, "%s or %s expected, but %s found [%d%s token]", 30 | YES.c_str(), NO.c_str(), compress(pa).c_str(), index, englishEnding(index).c_str()); 31 | 32 | if (ja != pa) 33 | quitf(_wa, "expected %s, found %s [%d%s token]", 34 | compress(ja).c_str(), compress(pa).c_str(), index, englishEnding(index).c_str()); 35 | } 36 | 37 | int extraInAnsCount = 0; 38 | while (!ans.seekEof()) { 39 | ans.readToken(); 40 | extraInAnsCount++; 41 | } 42 | 43 | int extraInOufCount = 0; 44 | while (!ouf.seekEof()) { 45 | ouf.readToken(); 46 | extraInOufCount++; 47 | } 48 | 49 | if (extraInAnsCount > 0) 50 | quitf(_wa, "Answer contains longer sequence [length = %d], but output contains %d elements", 51 | index + extraInAnsCount, index); 52 | 53 | if (extraInOufCount > 0) 54 | quitf(_wa, "Output contains longer sequence [length = %d], but answer contains %d elements", 55 | index + extraInOufCount, index); 56 | 57 | if (index == 0) 58 | quitf(_ok, "Empty output"); 59 | else if (index == 1) 60 | quitf(_ok, "%s", pa.c_str()); 61 | else 62 | quitf(_ok, "%d token(s): yes count is %d, no count is %d", index, yesCount, noCount); 63 | 64 | quitf(_fail, "Impossible case"); 65 | } 66 | -------------------------------------------------------------------------------- /test/algorithm/Prufer.h: -------------------------------------------------------------------------------- 1 | /* 2 | 最后修改: 3 | 20240429 4 | 测试环境: 5 | gcc11.2,c++11 6 | clang12.0,C++11 7 | msvc14.2,C++14 8 | */ 9 | #ifndef __OY_PRUFER__ 10 | #define __OY_PRUFER__ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace OY { 18 | namespace PRUFER { 19 | using size_type = uint32_t; 20 | struct Tree { 21 | struct node { 22 | size_type m_xor, m_deg; 23 | }; 24 | size_type m_vertex_cnt; 25 | std::vector m_info; 26 | template 27 | static std::vector decode(Iterator first, Iterator last) { 28 | size_type n = last - first + 2; 29 | std::vector res(n), deg(n); 30 | for (auto it = first; it != last; ++it) deg[*it]++; 31 | auto it = first; 32 | for (size_type i = 0; i != n; i++) 33 | if (!deg[i]) { 34 | size_type cur = i; 35 | do { 36 | if (it == last) 37 | res[cur] = n - 1; 38 | else 39 | res[cur] = *it++; 40 | cur = res[cur]; 41 | } while (!--deg[cur] && cur <= i); 42 | } 43 | res[n - 1] = -1; 44 | return res; 45 | } 46 | Tree(size_type vertex_cnt = 0) { resize(vertex_cnt); } 47 | void resize(size_type vertex_cnt) { 48 | if (!(m_vertex_cnt = vertex_cnt)) return; 49 | m_info.resize(m_vertex_cnt); 50 | } 51 | void add_edge(size_type a, size_type b) { m_info[a].m_deg++, m_info[b].m_deg++, m_info[a].m_xor ^= b, m_info[b].m_xor ^= a; } 52 | std::vector encode() { 53 | std::vector res; 54 | res.reserve(m_vertex_cnt - 1); 55 | for (size_type i = 0; i != m_vertex_cnt; i++) 56 | if (m_info[i].m_deg == 1) { 57 | size_type cur = i; 58 | do m_info[m_info[cur].m_xor].m_xor ^= cur, res.push_back(cur = m_info[cur].m_xor); 59 | while (--m_info[cur].m_deg == 1 && cur <= i); 60 | } 61 | res.pop_back(); 62 | return res; 63 | } 64 | }; 65 | } 66 | } 67 | 68 | #endif -------------------------------------------------------------------------------- /xmake.lua: -------------------------------------------------------------------------------- 1 | add_rules("mode.debug", "mode.release") 2 | 3 | task("merge") 4 | on_run(function() 5 | -- 生成时间戳 6 | local timestamp = os.date("%Y-%m-%d %H:%M:%S") 7 | 8 | -- 运行合并命令 9 | os.exec("xmake l cli.amalgamate -o . generator") 10 | 11 | -- 读取生成的内容 12 | local content = io.readfile("generator.h") 13 | 14 | -- 注入版本信息 15 | local header = string.format([[ 16 | // ================================================== 17 | // Auto-generated by xmake amalgamate 18 | // Time: %s 19 | // ================================================== 20 | #ifndef _SGPCET_ 21 | #define _SGPCET_ 22 | ]], timestamp) 23 | 24 | local footer = [[ 25 | #endif // _SGPCET_ 26 | ]] 27 | 28 | -- 重新写入文件 29 | io.writefile("generator.h", header .. content .. footer) 30 | end) 31 | set_menu { 32 | description = "合并头文件" 33 | } 34 | 35 | target("generator") 36 | set_kind("headeronly") 37 | add_includedirs("src") 38 | add_headerfiles("src/include_all.h") 39 | 40 | target("tests") 41 | set_kind("binary") 42 | add_cxxflags("/utf-8") 43 | set_languages("cxx17") 44 | add_files("test/*.cpp") 45 | add_files("test/catch/catch_amalgamated.cpp") 46 | add_includedirs("./test/catch") 47 | add_includedirs("src") 48 | add_deps("generator") 49 | 50 | target("val_test_val") 51 | set_kind("binary") 52 | set_targetdir("./test/validate") 53 | set_filename("val") 54 | add_files("./test/validate/val.cpp") 55 | 56 | target("val_test_test") 57 | set_kind("binary") 58 | set_targetdir("./test/validate") 59 | set_filename("test") 60 | add_includedirs("./test/catch") 61 | add_files("./test/validate/test.cpp") 62 | add_files("test/catch/catch_amalgamated.cpp") 63 | add_deps("val_test_val") 64 | 65 | task("validate_test") 66 | on_run(function () 67 | os.exec("xmake build val_test_val") 68 | os.exec("xmake build val_test_test") 69 | os.exec("./test/validate/test") 70 | os.rm("./test/validate/testcases") 71 | os.rm("./test/validate/validate") 72 | os.rm("./test/validate/val") 73 | os.rm("./test/validate/test") 74 | end) 75 | set_menu { 76 | description = "validate测试" 77 | } 78 | 79 | task("run_test") 80 | on_run(function() 81 | import("core.base.task") 82 | task.run("build", {target = "tests"}) 83 | os.exec("xmake run tests") 84 | os.exec("xmake validate_test") 85 | end) 86 | set_menu { 87 | description = "测试" 88 | } -------------------------------------------------------------------------------- /src/io/command_path.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_COMMAND_PATH_H_ 2 | #define _SGPCET_COMMAND_PATH_H_ 3 | 4 | #ifndef _SGPCET_PATH_H_ 5 | #include "path.h" 6 | #endif // !_SGPCET_PATH_H_ 7 | 8 | namespace generator { 9 | namespace io { 10 | 11 | 12 | class CommandPath { 13 | protected: 14 | Path _path; 15 | std::string _args; 16 | bool _enable_default_args; 17 | public: 18 | CommandPath() : _path(Path()), _args(""), _enable_default_args(true) {} 19 | CommandPath(CommandPath&& other) noexcept : 20 | _path(std::move(other._path)), _args(std::move(other._args)), _enable_default_args(std::move(other._enable_default_args)) {} 21 | CommandPath(const CommandPath& other) noexcept : 22 | _path(other._path), _args(other._args), _enable_default_args(other._enable_default_args) {} 23 | template::value>::type> 24 | CommandPath(T&& s) : _path(std::forward(s)), _args(""), _enable_default_args(true) {} 25 | template::value>::type> 26 | CommandPath(T&& s, std::string args) : _path(std::forward(s)), _args(args), _enable_default_args(false) {} 27 | CommandPath& operator=(CommandPath&& other) noexcept { 28 | if (this != &other) { 29 | _path = std::move(other._path); 30 | _args = std::move(other._args); 31 | _enable_default_args = std::move(other._enable_default_args); 32 | } 33 | return *this; 34 | } 35 | 36 | int run() { 37 | _path.full(); 38 | int code = std::system(command().c_str()); 39 | return code; 40 | } 41 | 42 | _SET_GET_VALUE(std::string, args) 43 | template 44 | void add_args(const Args&... others) { 45 | _args = tools::string_join(" ", _args, others...); 46 | } 47 | void clear_args() { _args.clear(); } 48 | 49 | _GET_VALUE(Path, path) 50 | template 51 | typename std::enable_if::value, void>::type 52 | set_path(T path) { 53 | _path = Path(path); 54 | } 55 | 56 | _SET_GET_VALUE(bool, enable_default_args) 57 | 58 | std::string command() { return tools::string_join(" ", _path, _args);} 59 | }; 60 | 61 | } // namespace io 62 | } // namespace generator 63 | 64 | #endif // !_SGPCET_COMMAND_PATH_H_ 65 | -------------------------------------------------------------------------------- /src/io/validate.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_VALIDATE_H_ 2 | #define _SGPCET_VALIDATE_H_ 3 | 4 | #ifndef _SGPCET_IO_REPORTER_H_ 5 | #include "io_reporter.h" 6 | #endif // !_SGPCET_IO_REPORTER_H_ 7 | #ifndef _SGPCET_PROGRAM_H_ 8 | #include "program.h" 9 | #endif //!_SGPCET_PROGRAM_H_ 10 | 11 | namespace generator { 12 | namespace io { 13 | template 14 | typename std::enable_if::value, void>::type 15 | __validate_impl(const std::vector& indices, T program, std::string case_name) { 16 | _msg::__info_msg(_msg::_defl, _msg::_ColorMsg("Validate", _enum::Color::Green)); 17 | __check_program_valid(program); 18 | std::unordered_map results; 19 | _ProgramTypeT validator = __validator_program(program); 20 | Path folder = __validate_folder(case_name); 21 | __create_directories(folder); 22 | for (int i : indices) { 23 | Path log = __path_join(folder, __end_with(i, _enum::_VAL)); 24 | Path input = __input_file_path(__path_join(__current_path(), case_name), i); 25 | _msg::__info_msg(_msg::_defl, tools::string_format("Checking input validity : %s", input.cname())); 26 | ReturnState state = __run_program(validator, input, _setting::_default_path, log, 27 | _setting::time_limit_inf, _enum::_VALIDATOR); 28 | _msg::_ColorMsg result_msg = __is_success(state.exit_code) ? _msg::_success : _msg::_fail; 29 | _msg::__info_msg(_msg::_defl, "Result : ", result_msg); 30 | results[i] = __is_success(state.exit_code); 31 | } 32 | __report_iov_summary_logs(results, _enum::_VALID); 33 | } 34 | 35 | template 36 | typename std::enable_if::value, void>::type 37 | validate(int start, int end, T program, std::string case_name = _setting::testcase_folder) { 38 | std::vector indices; 39 | Path folder = __path_join(__current_path(), case_name); 40 | for(int i = start; i <= end; i++) 41 | if (__input_file_exists(folder, i)) indices.emplace_back(i); 42 | __validate_impl(indices, program, case_name); 43 | } 44 | 45 | template 46 | typename std::enable_if::value, void>::type 47 | validate(T program, std::string case_name = _setting::testcase_folder) { 48 | __validate_impl(__get_all_inputs(case_name), program, case_name); 49 | } 50 | } // namespace io 51 | } // namespace generator 52 | 53 | #endif // !_SGPCET_VALIDATE_H_ 54 | -------------------------------------------------------------------------------- /test/test_geometry.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "test_basic.hpp" 3 | #include "algorithm/geometry_checker.h" 4 | using namespace generator::all; 5 | 6 | TEST_CASE("geometry format","[rand_geometry][format]") { 7 | init_gen(); 8 | auto p1 = __format_xy_range("[-100, 100]"); 9 | CHECK((p1.first == "[-100, 100]" && p1.second == "[-100, 100]")); 10 | auto p2 = __format_xy_range("[-100, 100] [-200, 200]"); 11 | CHECK((p2.first == "[-100, 100]" && p2.second == "[-200, 200]")); 12 | auto p3 = __format_xy_range("Y[-100, 100] x[-200, 200]"); 13 | CHECK((p3.first == "[-200, 200]" && p3.second == "[-100, 100]")); 14 | auto p4 = __format_xy_range("[-100, 100] x[-200, 200]"); 15 | CHECK((p4.first == "[-200, 200]" && p4.second == "[-100, 100]")); 16 | auto p5 = __format_xy_range("y[-100, 100] [-200, 200]"); 17 | CHECK((p5.first == "[-200, 200]" && p5.second == "[-100, 100]")); 18 | } 19 | 20 | bool convex_hull_check() { 21 | int n = rand_int(1, 100000); 22 | int limit = n * rand_int(10, 100); 23 | ConvexHull c(n); 24 | c.set_xy_limit(-n, n); 25 | c.gen(); 26 | return is_convex_hull(c); 27 | } 28 | 29 | TEST_CASE("rand convex hull", "[rand_geometry][ConvexHull]") { 30 | init_gen(); 31 | bool f = loop_check([]() { return convex_hull_check();}, 10); 32 | CHECK(f); 33 | } 34 | 35 | bool simple_polygon_check() { 36 | int n = rand_int(1, 10000); 37 | int limit = n * rand_int(10, 100); 38 | SimplePolygon p(n); 39 | p.set_xy_limit(-n, n); 40 | p.gen(); 41 | return is_simple_polygon(p); 42 | } 43 | 44 | TEST_CASE("rand simple polygon", "[rand_geometry][SimplePolygon]") { 45 | init_gen(); 46 | bool f = loop_check([]() { return simple_polygon_check();}, 10); 47 | CHECK(f); 48 | } 49 | 50 | class ConvexHullCheck : public ConvexHullGen { 51 | public: 52 | using Context = ConvexHullGen::Context; 53 | ConvexHullCheck(Context& points) : ConvexHullGen(points) {} 54 | std::vector> rand_no_origin_points(std::vector& x_vec, std::vector& y_vec) { 55 | return __rand_no_origin_points(x_vec, y_vec); 56 | } 57 | }; 58 | 59 | TEST_CASE("convex hull rand no origin points", "[rand_geometry][ConvexHull]") { 60 | init_gen(); 61 | ConvexHull c; 62 | c.set_geometry_generator(new ConvexHullCheck(c)); 63 | std::vector x_vec = {0, 0, 0, 1, 2, 3}; 64 | std::vector y_vec = {0, 0, 0, 4, 5, 6}; 65 | auto points = dynamic_cast(c.generator())->rand_no_origin_points(x_vec, y_vec); 66 | for (auto& p : points) CHECK(p != Point(0, 0)); 67 | x_vec = {0, 0, 0, -1, -2, -3}; 68 | y_vec = {0, 0, 0, 4, 5, 6}; 69 | points = dynamic_cast(c.generator())->rand_no_origin_points(x_vec, y_vec); 70 | for (auto& p : points) CHECK(p!= Point(0, 0)); 71 | } -------------------------------------------------------------------------------- /src/io/command_func.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_COMMAND_FUNC_H_ 2 | #define _SGPCET_COMMAND_FUNC_H_ 3 | 4 | #ifndef _SGPCET_COMMON_H_ 5 | #include "basic/common.h" 6 | #endif // !_SGPCET_COMMON_H_ 7 | #ifndef _SGPCET_MACRO_H_ 8 | #include "basic/macro.h" 9 | #endif // !_SGPCET_MACRO_H_ 10 | 11 | namespace generator { 12 | namespace io { 13 | template 14 | struct IsFunctionConvertible { 15 | static constexpr bool value = std::is_convertible>::value; 16 | }; 17 | 18 | class CommandFunc { 19 | protected: 20 | std::function _func; 21 | std::string _args; 22 | bool _enable_default_args; 23 | public: 24 | CommandFunc() : _func(nullptr), _args(""), _enable_default_args(true) {} 25 | CommandFunc(CommandFunc&& other) noexcept : 26 | _func(std::move(other._func)), _args(std::move(other._args)), _enable_default_args(std::move(other._enable_default_args)) {} 27 | CommandFunc(const CommandFunc& other) noexcept : 28 | _func(other._func), _args(other._args), _enable_default_args(other._enable_default_args) {} 29 | template::value>::type> 30 | CommandFunc(T&& func) : _func(std::forward(func)), _args(""), _enable_default_args(true) {} 31 | template::value>::type> 32 | CommandFunc(T&& func, std::string args) : _func(std::forward(func)), _args(args), _enable_default_args(false) {} 33 | CommandFunc& operator=(CommandFunc&& other) noexcept { 34 | if (this != &other) { 35 | _func = std::move(other._func); 36 | _args = std::move(other._args); 37 | _enable_default_args = std::move(other._enable_default_args); 38 | } 39 | return *this; 40 | } 41 | 42 | _SET_GET_VALUE(std::string, args) 43 | template 44 | void add_args(const Args&... others) { 45 | _args = tools::string_join(" ", _args, others...); 46 | } 47 | void clear_args() { _args.clear(); } 48 | 49 | _GET_VALUE(std::function, func) 50 | template 51 | typename std::enable_if::value, void>::type 52 | set_func(T func) { 53 | _func = std::function(func); 54 | } 55 | 56 | _SET_GET_VALUE(bool, enable_default_args) 57 | 58 | }; 59 | } // namespace io 60 | 61 | } // namespace generator 62 | 63 | 64 | #endif // !_SGPCET_COMMAND_FUNC_H_ 65 | -------------------------------------------------------------------------------- /src/geometry/simple_polygon.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_SIMPLE_POLYGON_H_ 2 | #define _SGPCET_SIMPLE_POLYGON_H_ 3 | 4 | #ifndef _SGPCET_POINTS_H_ 5 | #include "points.h" 6 | #endif //!_SGPCET_POINTS_H_ 7 | #ifndef _SGPCET_GEOMETRY_ALGORITHM_H_ 8 | #include "geometry_algorithm.h" 9 | #endif //!_SGPCET_GEOMETRY_ALGORITHM_H_ 10 | 11 | namespace generator { 12 | namespace rand_geometry { 13 | 14 | template ::value>::type> 15 | class SimplePolygon; 16 | 17 | template ::value>::type> 18 | class SimplePolygonGen : public BasicPolygonGen { 19 | public: 20 | using Context = SimplePolygon; 21 | using Super = BasicPolygonGen; 22 | SimplePolygonGen(Context& points) : BasicPolygonGen(points) {} 23 | protected: 24 | virtual void __generate_geometry() override { 25 | _CONTEXT_GET(node_count); 26 | _CONTEXT_GET(x_left_limit); 27 | _CONTEXT_GET(x_right_limit); 28 | _CONTEXT_GET(y_left_limit); 29 | _CONTEXT_GET(y_right_limit); 30 | RandomPoints p(node_count, x_left_limit, x_right_limit, y_left_limit, y_right_limit); 31 | p.gen(); 32 | _CONTEXT_GET_REF(points); 33 | points = p.points(); 34 | Point center = __get_center(points); 35 | __polar_angle_sort(points, center); 36 | } 37 | 38 | Point __get_center(std::vector>& points) { 39 | _ResultTypeT x_sum = 0; 40 | _ResultTypeT y_sum = 0; 41 | for (auto& p : points) { 42 | x_sum += p.x(); 43 | y_sum += p.y(); 44 | } 45 | _ResultTypeT n = points.size(); 46 | return Point(x_sum / n, y_sum / n); 47 | } 48 | }; 49 | 50 | template 51 | class SimplePolygon : public RandomPoints { 52 | public: 53 | using _Self = SimplePolygon; 54 | _OUTPUT_FUNCTION(_Self) 55 | public: 56 | SimplePolygon(int node_count = 1, T x_left_limit = 0, T x_right_limit = 0, T y_left_limit = 0, T y_right_limit = 0) : 57 | RandomPoints(node_count, x_left_limit, x_right_limit, y_left_limit, y_right_limit) 58 | { 59 | _GEOMETRY_DEFAULT 60 | } 61 | 62 | _DISABLE_SAME_POINT 63 | _OUTPUT_FUNCTION_SETTING(_Self) 64 | protected: 65 | _DEFAULT_GEOMETRY_GEN_FUNC(SimplePolygon) 66 | }; 67 | } // namespace rand_geometry 68 | } // namespace generator 69 | 70 | #endif //!_SGPCET_SIMPLE_POLYGON_H_ 71 | -------------------------------------------------------------------------------- /test/algorithm/Manacher.h: -------------------------------------------------------------------------------- 1 | /* 2 | 最后修改: 3 | 20231207 4 | 测试环境: 5 | gcc11.2,c++11 6 | clang12.0,C++11 7 | msvc14.2,C++14 8 | */ 9 | #ifndef __OY_MANACHER__ 10 | #define __OY_MANACHER__ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace OY { 18 | template 19 | struct Manacher { 20 | uint32_t m_length; 21 | std::vector m_odd_arm, m_even_arm; 22 | Manacher() = default; 23 | template 24 | Manacher(uint32_t length, InitMapping mapping) { resize(length, mapping); } 25 | template 26 | Manacher(Iterator first, Iterator last) { reset(first, last); } 27 | template 28 | Manacher(const Sequence &seq) : Manacher(seq.begin(), seq.end()) {} 29 | template 30 | void resize(uint32_t length, InitMapping mapping) { 31 | m_length = length; 32 | if constexpr (Odd) { 33 | m_odd_arm.clear(), m_odd_arm.reserve(m_length); 34 | for (int l = -1, r = -1, i = 0; i != m_length; i++) { 35 | int k = i <= r ? std::min(m_odd_arm[l + r - i], r - i) + 1 : 1; 36 | while (k <= i && k < m_length - i && mapping(i - k) == mapping(i + k)) k++; 37 | m_odd_arm.push_back(k - 1); 38 | if (i + k - 1 > r) l = i - k + 1, r = i + k - 1; 39 | } 40 | } 41 | if constexpr (Even) { 42 | m_even_arm.clear(), m_even_arm.reserve(m_length); 43 | for (int l = 0, r = -1, i = 0; i != m_length; i++) { 44 | int k = i <= r ? std::min(m_even_arm[l + r - i + 1], r - i + 1) + 1 : 1; 45 | while (k <= i && k < m_length - i + 1 && mapping(i - k) == mapping(i + k - 1)) k++; 46 | m_even_arm.push_back(k - 1); 47 | if (i + k - 2 > r) l = i - k + 1, r = i + k - 2; 48 | } 49 | } 50 | } 51 | template 52 | void reset(Iterator first, Iterator last) { 53 | resize(last - first, [&](uint32_t i) { return *(first + i); }); 54 | } 55 | uint32_t query_max_odd_arm(uint32_t center) const { 56 | static_assert(Odd, "Odd Must Be True"); 57 | return m_odd_arm[center]; 58 | } 59 | uint32_t query_max_even_arm(uint32_t center_l, uint32_t center_r) const { 60 | static_assert(Even, "Even Must Be True"); 61 | return m_even_arm[center_r]; 62 | } 63 | bool query(uint32_t left, uint32_t right) const { 64 | if ((left ^ right) & 1) 65 | return m_even_arm[(left + right + 1) >> 1] > (right - left) >> 1; 66 | else 67 | return m_odd_arm[(left + right) >> 1] >= (right - left) >> 1; 68 | } 69 | }; 70 | } 71 | 72 | #endif -------------------------------------------------------------------------------- /test/test_array.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "test_basic.hpp" 3 | #include "algorithm/Manacher.h" 4 | using namespace generator::all; 5 | 6 | TEST_CASE("rand sum", "[rand_array][rand_sum]") { 7 | init_gen(); 8 | std::vector v = rand_sum(100, 1e10, -1e9, 1e9); 9 | CHECK(v.size() == 100); 10 | long long sum = 0; 11 | for (auto& x : v) { 12 | sum += x; 13 | CHECK((-1e9 <= x && x <= 1e9)); 14 | } 15 | CHECK(sum == 1e10); 16 | } 17 | 18 | bool palindrome_check() { 19 | int n = rand_int(1, 1e5); 20 | int p = rand_int(1, n); 21 | auto s = rand_palindrome(n, p); 22 | if (s.size() != n) return false; 23 | OY::Manacher m(s); 24 | int max_p = 0; 25 | for (int i = 0; i < n; i++) { 26 | max_p = std::max(max_p, (int)m.query_max_odd_arm(i) * 2 + 1); 27 | if (i + 1 < n) max_p = std::max(max_p, (int)m.query_max_even_arm(i, i + 1) * 2); 28 | } 29 | return max_p >= p; 30 | } 31 | 32 | TEST_CASE("rand palindrome", "[rand_array][rand_palindrome]") { 33 | init_gen(); 34 | bool f = loop_check([&]() { return palindrome_check();}, 10); 35 | CHECK(f); 36 | } 37 | 38 | bool bracket_seq_check() { 39 | int n = rand_even(1, 1e5); 40 | std::vector bracket_seqs = {"()", "[]", "{}"}; 41 | int seqs_count = rand_int(1, 3); 42 | std::string barcket = ""; 43 | for (int i = 0; i < seqs_count; i++) barcket += bracket_seqs[i]; 44 | auto s = rand_bracket_seq(n, barcket); 45 | if (s.size() != n) return false; 46 | std::stack st; 47 | for (auto& c : s) { 48 | bool match = false; 49 | for (int i = 0; i < seqs_count; i++) { 50 | if (c == bracket_seqs[i][0]) { 51 | st.push(bracket_seqs[i][1]); 52 | match = true; 53 | } 54 | else if (c == bracket_seqs[i][1]) { 55 | if (st.empty() || st.top() != c) return false; 56 | st.pop(); 57 | match = true; 58 | } 59 | } 60 | if (!match) return false; 61 | } 62 | if (!st.empty()) return false; 63 | return true; 64 | } 65 | 66 | TEST_CASE("rand bracket sequence", "[rand_array][rand_bracket_seq]") { 67 | init_gen(); 68 | bool f = loop_check([]() { return bracket_seq_check(); }, 10); 69 | CHECK(f); 70 | } 71 | 72 | bool shuffle_index_check() { 73 | int n = rand_int(1, 1e3); 74 | int sum = rand_int(1, 1e5); 75 | std::vector v = rand_sum(n, sum); 76 | int offset = rand_int(1, 10); 77 | std::vector count(n); 78 | std::vector index = shuffle_index(v, offset); 79 | for (auto& i : index) { 80 | int p = i - offset; 81 | if (p < 0 || p >= n) return false; 82 | count[p]++; 83 | } 84 | for (int i = 0; i < n; i++) { 85 | if (count[i]!= v[i]) return false; 86 | } 87 | return true; 88 | } 89 | 90 | TEST_CASE("shuffle vector index", "[rand_array][shuffle_index]") { 91 | init_gen(); 92 | bool f = loop_check([]() { return shuffle_index_check(); }, 10); 93 | CHECK(f); 94 | } -------------------------------------------------------------------------------- /src/geometry/geometry_strategy.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_GEOMETRY_STRATEGY_H_ 2 | #define _SGPCET_GEOMETRY_STRATEGY_H_ 3 | 4 | #ifndef _SGPCET_MACRO_H_ 5 | #include "basic/macro.h" 6 | #endif // !_SGPCET_MACRO_H_ 7 | #ifndef _SGPCET_GEN_STRATEGY_H_ 8 | #include "basic/gen_strategy.h" 9 | #endif // !_SGPCET_GEN_STRATEGY_H_ 10 | 11 | namespace generator { 12 | namespace rand_geometry { 13 | template class GeoType, typename T> 14 | class BasicGeometryGen : public tools::_BasicGen> { 15 | public: 16 | BasicGeometryGen(GeoType& context) : tools::_BasicGen>(context) {} 17 | virtual void generate() override { 18 | _msg::OutStream geometry_log(false); 19 | _msg::_defl.swap(geometry_log); 20 | __init(); 21 | __generate_geometry(); 22 | _msg::_defl.swap(geometry_log); 23 | }; 24 | protected: 25 | virtual void __init() { 26 | __self_init(); 27 | __judge_limits(); 28 | }; 29 | 30 | void __judge_limits() { 31 | __judge_comman_limit(); 32 | __judge_self_limit(); 33 | } 34 | 35 | virtual void __judge_comman_limit() { 36 | _CONTEXT_GET(x_left_limit); 37 | _CONTEXT_GET(x_right_limit); 38 | _CONTEXT_GET(y_left_limit); 39 | _CONTEXT_GET(y_right_limit); 40 | if (x_left_limit > x_right_limit) 41 | _msg::__fail_msg(_msg::_defl, tools::string_format( "range [%s, %s] for x-coordinate is invalid.", 42 | std::to_string(x_left_limit).c_str(), std::to_string(x_right_limit).c_str())); 43 | if (y_left_limit > y_right_limit) 44 | _msg::__fail_msg(_msg::_defl, tools::string_format( "range [%s, %s] for y-coordinate is invalid.", 45 | std::to_string(y_left_limit).c_str(), std::to_string(y_right_limit).c_str())); 46 | } 47 | 48 | virtual void __self_init() {} 49 | 50 | virtual void __judge_self_limit() {} 51 | 52 | virtual void __generate_geometry() { 53 | _msg::__fail_msg(_msg::_defl, "unsupport geometry generator."); 54 | }; 55 | 56 | T __rand_x() { 57 | _CONTEXT_GET(x_left_limit); 58 | _CONTEXT_GET(x_right_limit); 59 | return rand_numeric::__rand_value(x_left_limit, x_right_limit); 60 | } 61 | T __rand_y() { 62 | _CONTEXT_GET(y_left_limit); 63 | _CONTEXT_GET(y_right_limit); 64 | return rand_numeric::__rand_value(y_left_limit, y_right_limit); 65 | } 66 | }; 67 | 68 | class _GeometryGenSwitch : public tools::_GenSwitch { 69 | public: 70 | void set_geometry_generator(tools::_Gen* gen) { 71 | __delete_generator(); 72 | _generator = gen; 73 | } 74 | }; 75 | } // namespace rand_geometry 76 | } // namespace generator 77 | 78 | #endif // !_SGPCET_GEOMETRY_STRATEGY_H_ 79 | -------------------------------------------------------------------------------- /src/graph/unweight.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_UNWEIGHT_H_ 2 | #define _SGPCET_UNWEIGHT_H_ 3 | 4 | #ifndef _SGPCET_ALL_TREE_GRAPH_H_ 5 | #include "all_tree_graph.h" 6 | #endif // !_SGPCET_ALL_TREE_GRAPH_H_ 7 | 8 | namespace generator { 9 | namespace rand_graph { 10 | namespace unweight { 11 | using Edge = basic::_Edge; 12 | using NodeWeight = basic::_Node; 13 | using TreeGenerator = _enum::TreeGenerator; 14 | using TreeGen = basic::TreeGen; 15 | using RandomFatherGen = basic::RandomFatherGen; 16 | using PrueferGen = basic::PrueferGen; 17 | using Tree = basic::Tree; 18 | using ChainGen = basic::ChainGen; 19 | using Chain = basic::Chain; 20 | using FlowerGen = basic::FlowerGen; 21 | using Flower = basic::Flower; 22 | using HeightTreeGen = basic::HeightTreeGen; 23 | using HeightTree = basic::HeightTree; 24 | using MaxDegreeTreeGen = basic::MaxDegreeTreeGen; 25 | using MaxDegreeTree = basic::MaxDegreeTree; 26 | using MaxSonTreeGen = basic::MaxSonTreeGen; 27 | using MaxSonTree = basic::MaxSonTree; 28 | using GraphGen = basic::GraphGen; 29 | using Graph = basic::Graph; 30 | using BipartiteGraphGen = basic::BipartiteGraphGen; 31 | using BipartiteGraph = basic::BipartiteGraph; 32 | using DAGGen = basic::DAGGen; 33 | using DAG = basic::DAG; 34 | using CycleGraphGen = basic::CycleGraphGen; 35 | using CycleGraph = basic::CycleGraph; 36 | using WheelGraphGen = basic::WheelGraphGen; 37 | using WheelGraph = basic::WheelGraph; 38 | using GridGraphGen = basic::GridGraphGen; 39 | using GridGraph = basic::GridGraph; 40 | using PseudoTreeGen = basic::PseudoTreeGen; 41 | using PseudoTree = basic::PseudoTree; 42 | using PseudoInTreeGen = basic::PseudoInTreeGen; 43 | using PseudoInTree = basic::PseudoInTree; 44 | using PseudoOutTreeGen = basic::PseudoOutTreeGen; 45 | using PseudoOutTree = basic::PseudoOutTree; 46 | using CactusGen = basic::CactusGen; 47 | using Cactus = basic::Cactus; 48 | using LinkGen = basic::LinkGen; 49 | using Link = basic::Link; 50 | using TreeLinkGen = basic::TreeLinkGen; 51 | using TreeLink = basic::TreeLink; 52 | using ForestGen = basic::ForestGen; 53 | using Forest = basic::Forest; 54 | using FlowerChainGen = basic::FlowerChainGen; 55 | using FlowerChain = basic::FlowerChain; 56 | } // namespace unweight 57 | } // namespace rand_graph 58 | } // namespace generator 59 | 60 | #endif // !_SGPCET_UNWEIGHT_H_ 61 | -------------------------------------------------------------------------------- /src/geometry/line_segment.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_LINE_SEGMENT_H_ 2 | #define _SGPCET_LINE_SEGMENT_H_ 3 | 4 | #ifndef _SGPCET_POINTS_H_ 5 | #include "points.h" 6 | #endif //!_SGPCET_POINTS_H_ 7 | 8 | namespace generator { 9 | namespace rand_geometry { 10 | template 11 | class _2Points { 12 | protected: 13 | using _Self = _2Points; 14 | _OUTPUT_FUNCTION(_Self) 15 | Point _start, _end; 16 | public: 17 | _2Points() { 18 | _DEFAULT_OUTPUT 19 | } 20 | 21 | _2Points(const Point& start, const Point& end) : _start(start), _end(end) { 22 | _DEFAULT_OUTPUT 23 | } 24 | 25 | _SET_GET_VALUE(Point, start) 26 | _SET_GET_VALUE(Point, end) 27 | 28 | Point to_vector() { return _end - _start; } 29 | 30 | _ResultTypeT operator^(const Point& b) const { return (_end - _start) ^ b; } 31 | _ResultTypeT operator^(const _2Points& l) const { return (_end - _start) ^ (l._end - l._start); } 32 | _ResultTypeT operator*(const Point& b) const { return (_end - _start) * b; } 33 | _ResultTypeT operator*(const _2Points& l) const { return (_end - _start) * (l._end - l._start); } 34 | 35 | void default_output(std::ostream& os) const { 36 | os << _start << " " << _end; 37 | } 38 | 39 | _GEOMETRY_IN_RAND_FUNC(RandomPoints) 40 | _OUTPUT_FUNCTION_SETTING(_Self) 41 | protected: 42 | void __rand(RandomPoints& p) { 43 | p.set_node_count(2); 44 | p.set_same_point(false); 45 | p.gen(); 46 | auto points = p.points(); 47 | _start = points[0]; 48 | _end = points[1]; 49 | } 50 | }; 51 | 52 | template ::value>::type> 53 | class Line : public _2Points { 54 | protected: 55 | using _Self = Line; 56 | _OUTPUT_FUNCTION(_Self) 57 | public: 58 | Line() : _2Points() { 59 | _DEFAULT_OUTPUT 60 | } 61 | Line(const Point& start, const Point& end) : _2Points(start, end) { 62 | _DEFAULT_OUTPUT 63 | } 64 | 65 | _OUTPUT_FUNCTION_SETTING(_Self) 66 | }; 67 | 68 | _GEOMETRY_OUT_RAND_FUNC(rand_line, Line) 69 | 70 | template ::value>::type> 71 | class Segment : public _2Points { 72 | protected: 73 | using _Self = Segment; 74 | _OUTPUT_FUNCTION(_Self) 75 | public: 76 | Segment() : _2Points() { 77 | _DEFAULT_OUTPUT 78 | } 79 | Segment(const Point& start, const Point& end) : _2Points(start, end) { 80 | _DEFAULT_OUTPUT 81 | } 82 | 83 | _OUTPUT_FUNCTION_SETTING(_Self) 84 | }; 85 | 86 | _GEOMETRY_OUT_RAND_FUNC(rand_segment, Segment) 87 | } // namespace rand_geometry 88 | } // namespace generator 89 | 90 | #endif // !_SGPCET_LINE_SEGMENT_H_ 91 | -------------------------------------------------------------------------------- /src/graph/edge.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_EDGE_H_ 2 | #define _SGPCET_EDGE_H_ 3 | 4 | #ifndef _SGPCET_MACRO_H_ 5 | #include "basic/macro.h" 6 | #endif // !_SGPCET_MACRO_H_ 7 | 8 | namespace generator { 9 | namespace rand_graph { 10 | namespace basic { 11 | class _BasicEdge { 12 | protected: 13 | int _u, _v; 14 | bool _swap_node; 15 | public: 16 | _BasicEdge(int u, int v) : _u(u), _v(v), _swap_node(false) {} 17 | 18 | _SET_GET_VALUE(int, u) 19 | _SET_GET_VALUE(int, v) 20 | _SET_GET_VALUE(bool, swap_node) 21 | 22 | friend bool operator==(const _BasicEdge a, const _BasicEdge b) { 23 | return a._u == b._u && a._v == b._v; 24 | } 25 | friend bool operator!=(const _BasicEdge a, const _BasicEdge b) { 26 | return !(a == b); 27 | } 28 | friend bool operator<(const _BasicEdge a, const _BasicEdge b) { 29 | if (a._u == b._u) return a._v < b._v; 30 | return a._u < b._u; 31 | } 32 | friend bool operator<=(const _BasicEdge a, const _BasicEdge b) { 33 | return a == b || a < b; 34 | } 35 | friend bool operator>(const _BasicEdge a, const _BasicEdge b) { 36 | return !(a <= b); 37 | } 38 | friend bool operator>=(const _BasicEdge a, const _BasicEdge b) { 39 | return !(a < b); 40 | } 41 | }; 42 | 43 | template 44 | class _Edge : public _BasicEdge { 45 | protected: 46 | using _Self = _Edge; 47 | T _w; 48 | _OUTPUT_FUNCTION(_Self) 49 | public: 50 | _Edge(int u, int v) : _BasicEdge(u, v), _w(T()) { 51 | _DEFAULT_OUTPUT 52 | } 53 | _Edge(int u, int v, T w) : _BasicEdge(u, v), _w(w) { 54 | _DEFAULT_OUTPUT 55 | } 56 | 57 | _SET_GET_VALUE(T, w) 58 | 59 | std::tuple edge() const { return std::make_tuple(_u, _v, _w); } 60 | 61 | void default_output(std::ostream& os) const { 62 | if (_swap_node) os << _v << " " << _u << " " << _w; 63 | else os << _u << " " << _v << " " << _w; 64 | } 65 | 66 | _OUTPUT_FUNCTION_SETTING(_Self) 67 | }; 68 | 69 | template<> 70 | class _Edge : public _BasicEdge { 71 | protected: 72 | using _Self = _Edge; 73 | _OUTPUT_FUNCTION(_Self) 74 | public: 75 | _Edge(int u, int v) : _BasicEdge(u, v) { 76 | _DEFAULT_OUTPUT 77 | } 78 | 79 | std::tuple edge() const { return std::make_tuple(_u, _v); } 80 | 81 | void default_output(std::ostream& os) const { 82 | if (_swap_node) os << _v << " " << _u ; 83 | else os << _u << " " << _v ; 84 | } 85 | 86 | _OUTPUT_FUNCTION_SETTING(_Self) 87 | }; 88 | } // namespace basic 89 | } // namespace rand_graph 90 | } // namespace generator 91 | 92 | #endif // !_SGPCET_EDGE_H_ 93 | -------------------------------------------------------------------------------- /src/geometry/range_format.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_RANGE_FORMAT_H_ 2 | #define _SGPCET_RANGE_FORMAT_H_ 3 | 4 | #ifndef _SGPCET_GEOMETRY_BASIC_H_ 5 | #include "geometry_basic.h" 6 | #endif //!_SGPCET_GEOMETRY_BASIC_H_ 7 | #ifndef _SGPCET_NUMBER_FORMAT_H_ 8 | #include "rand/number_format.h" 9 | #endif //!_SGPCET_NUMBER_FORMAT_H_ 10 | 11 | namespace generator { 12 | namespace rand_geometry { 13 | struct _RangeString { 14 | std::string range; 15 | std::string type; 16 | _RangeString(std::string range = "", std::string type = "") : range(range), type(type) {} 17 | 18 | bool any_type() { return type == ""; } 19 | bool empty_range() { return range == ""; } 20 | }; 21 | 22 | _RangeString __find_range(std::string s, size_t& pos_start, std::vector& types) { 23 | size_t open = s.find_first_of("[(", pos_start); 24 | size_t close = s.find_first_of(")]", pos_start); 25 | if (open == std::string::npos && close == std::string::npos) 26 | return _RangeString(); 27 | std::string range = s.substr(open, close - open + 1); 28 | if (open == std::string::npos || close == std::string::npos) 29 | _msg::__fail_msg(_msg::_defl, "%s is not a vaild range.", range.c_str()); 30 | std::string mark = s.substr(pos_start, open - pos_start); 31 | pos_start = close + 1; 32 | std::string range_type = ""; 33 | for (auto& type : types) { 34 | if (mark.find_first_of(type) != std::string::npos) { 35 | if (range_type != "" && range_type != type) 36 | return _RangeString(range); 37 | range_type = type; 38 | } 39 | } 40 | return _RangeString(range, range_type); 41 | } 42 | 43 | std::pair __format_xy_range(std::string format) { 44 | std::vector types = { "xX", "yY" }; 45 | size_t pos_start = 0; 46 | std::vector<_RangeString> ranges; 47 | while (pos_start < format.length()) { 48 | _RangeString range = __find_range(format, pos_start, types); 49 | if (range.empty_range()) break; 50 | ranges.push_back(range); 51 | } 52 | if (ranges.size() == 0) _msg::__fail_msg(_msg::_defl, "no range found."); 53 | if (ranges.size() > 2) _msg::__fail_msg(_msg::_defl, "too many ranges found."); 54 | if (ranges.size() == 1) { 55 | if (!ranges[0].any_type()) 56 | _msg::__fail_msg(_msg::_defl, tools::string_format("only found %c range.", ranges[0].type[0])); 57 | return std::make_pair(ranges[0].range, ranges[0].range); 58 | } 59 | if (!ranges[0].any_type() && ranges[0].type == ranges[1].type) 60 | _msg::__fail_msg(_msg::_defl, tools::string_format("found %c range twice.", ranges[0].type[0])); 61 | auto result = std::make_pair(ranges[0].range, ranges[1].range); 62 | // a a 63 | // a x -> x a 64 | // a y 65 | // x a 66 | // x y 67 | // y a -> a y 68 | // y x -> x y 69 | if (ranges[0].type == types[1] || ranges[1].type == types[0]) std::swap(result.first, result.second); 70 | return result; 71 | } 72 | } // namespace rand_geometry 73 | } // namespace generator 74 | 75 | #endif // !_SGPCET_RANGE_FORMAT_H_ 76 | -------------------------------------------------------------------------------- /src/graph/graph.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_GRAPH_H_ 2 | #define _SGPCET_GRAPH_H_ 3 | 4 | #ifndef _SGPCET_GEN_GRAPH_H_ 5 | #include "gen_graph.h" 6 | #endif // !_SGPCET_GEN_GRAPH_H_ 7 | 8 | namespace generator { 9 | namespace rand_graph { 10 | namespace basic { 11 | template 12 | class Graph; 13 | 14 | template 15 | class GraphGen : public BasicGraphGen { 16 | protected: 17 | using Context = Graph; 18 | public: 19 | GraphGen(Context& graph) : BasicGraphGen(graph) {} 20 | }; 21 | 22 | template 23 | class Graph : public _GenGraph { 24 | protected: 25 | using _Self = Graph; 26 | _OUTPUT_FUNCTION(_Self) 27 | _DEF_GEN_FUNCTION 28 | public: 29 | template = 0> 30 | Graph(int node_count = 1, int edge_count = 0, int begin_node = 1, 31 | NodeGenFunction nodes_weight_function = nullptr, 32 | EdgeGenFunction edges_weight_function = nullptr) : 33 | _GenGraph(node_count, edge_count, begin_node, 34 | false, false, false, false, true, 35 | nodes_weight_function, edges_weight_function) 36 | { 37 | _TREE_GRAPH_DEFAULT 38 | } 39 | 40 | template = 0> 41 | Graph(int node_count = 1, int edge_count = 0, int begin_node = 1, 42 | EdgeGenFunction edges_weight_function = nullptr) : 43 | _GenGraph(node_count, edge_count, begin_node, 44 | false, false, false, false, true, 45 | edges_weight_function) 46 | { 47 | _TREE_GRAPH_DEFAULT 48 | } 49 | 50 | template = 0> 51 | Graph(int node_count = 1, int edge_count = 0, int begin_node = 1, 52 | NodeGenFunction nodes_weight_function = nullptr) : 53 | _GenGraph(node_count, edge_count, begin_node, 54 | false, false, false, false, true, 55 | nodes_weight_function) 56 | { 57 | _TREE_GRAPH_DEFAULT 58 | } 59 | 60 | template = 0> 61 | Graph(int node_count = 1, int edge_count = 0, int begin_node = 1) : 62 | _GenGraph(node_count, edge_count, begin_node, 63 | false, false, false, false, true) 64 | { 65 | _TREE_GRAPH_DEFAULT 66 | } 67 | _OUTPUT_FUNCTION_SETTING(_Self) 68 | protected: 69 | _DEFAULT_GRAPH_GEN_FUNC(Graph) 70 | }; 71 | } // namespace basic 72 | } // namespace rand_graph 73 | } // namespace generator 74 | 75 | #endif // !_SGPCET_GRAPH_H_ 76 | -------------------------------------------------------------------------------- /src/graph/chain.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_CHAIN_H_ 2 | #define _SGPCET_CHAIN_H_ 3 | 4 | #ifndef _SGPCET_TREE_H_ 5 | #include "tree.h" 6 | #endif // !_SGPCET_TREE_H_ 7 | 8 | namespace generator { 9 | namespace rand_graph { 10 | namespace basic { 11 | template 12 | class Chain; 13 | 14 | template 15 | class ChainGen : public BasicRandomFatherGen { 16 | protected: 17 | using Context = Chain; 18 | public: 19 | ChainGen(Context& tree) : BasicRandomFatherGen(tree) {} 20 | protected: 21 | virtual void __random_father() override { 22 | for (int i = 1; i < this->_context.node_count(); i++) { 23 | this->__add_edge(this->_rank[i - 1], this->_rank[i]); 24 | } 25 | } 26 | }; 27 | 28 | template 29 | class Chain : public _GenTree { 30 | protected: 31 | using _Self = Chain; 32 | _OUTPUT_FUNCTION(_Self) 33 | _DEF_GEN_FUNCTION 34 | public: 35 | template = 0> 36 | Chain(int node = 1, int begin_node = 1, bool is_rooted = false, int root = 1, 37 | NodeGenFunction nodes_weight_function = nullptr, 38 | EdgeGenFunction edges_weight_function = nullptr) : 39 | _GenTree(node, begin_node, is_rooted, root, 40 | nodes_weight_function, edges_weight_function) 41 | { 42 | _TREE_GRAPH_DEFAULT 43 | } 44 | 45 | template = 0> 46 | Chain(int node = 1, int begin_node = 1, bool is_rooted = false, int root = 1, 47 | EdgeGenFunction edges_weight_function = nullptr) : 48 | _GenTree(node, begin_node, is_rooted, root, edges_weight_function) 49 | { 50 | _TREE_GRAPH_DEFAULT 51 | } 52 | 53 | template = 0> 54 | Chain(int node = 1, int begin_node = 1, bool is_rooted = false, int root = 1, 55 | NodeGenFunction nodes_weight_function = nullptr) : 56 | _GenTree(node, begin_node, is_rooted, root, nodes_weight_function) 57 | { 58 | _TREE_GRAPH_DEFAULT 59 | } 60 | 61 | template = 0> 62 | Chain(int node = 1, int begin_node = 1, bool is_rooted = false, int root = 1) : 63 | _GenTree(node, begin_node, is_rooted, root) 64 | { 65 | _TREE_GRAPH_DEFAULT 66 | } 67 | _OUTPUT_FUNCTION_SETTING(_Self) 68 | protected: 69 | _DEFAULT_GRAPH_GEN_FUNC(Chain) 70 | }; 71 | } // namespace basic 72 | } // namespace rand_graph 73 | } // namespace generator 74 | 75 | #endif // !_SGPCET_CHAIN_H_ 76 | -------------------------------------------------------------------------------- /src/graph/gen_function.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_GEN_FUNCTION_H_ 2 | #define _SGPCET_GEN_FUNCTION_H_ 3 | 4 | #ifndef _SGPCET_COMMON_H_ 5 | #include "basic/common.h" 6 | #endif // !_SGPCET_COMMON_H_ 7 | #ifndef _SGPCET_LOGGER_H_ 8 | #include "log/logger.h" 9 | #endif // !_SGPCET_LOGGER_H_ 10 | #ifndef _SGPCET_WEIGHT_TYPE_H_ 11 | #include "weight_type.h" 12 | #endif // !_SGPCET_WEIGHT_TYPE_H_ 13 | 14 | namespace generator { 15 | namespace rand_graph { 16 | namespace basic { 17 | template 18 | class _RandomFunction { 19 | protected: 20 | _DEF_GEN_FUNCTION 21 | NodeGenFunction _nodes_weight_function; 22 | EdgeGenFunction _edges_weight_function; 23 | public: 24 | _RandomFunction( 25 | NodeGenFunction nodes_weight_function, 26 | EdgeGenFunction edges_weight_function) : 27 | _nodes_weight_function(nodes_weight_function), 28 | _edges_weight_function(edges_weight_function) 29 | {} 30 | 31 | virtual ~_RandomFunction() = default; 32 | 33 | template = 0> 34 | void set_nodes_weight_function(NodeGenFunction nodes_weight_function) { 35 | _nodes_weight_function = nodes_weight_function; 36 | } 37 | 38 | template = 0> 39 | void set_edges_weight_function(EdgeGenFunction edges_weight_function) { 40 | _edges_weight_function = edges_weight_function; 41 | } 42 | 43 | _GET_VALUE(NodeGenFunction, nodes_weight_function) 44 | _GET_VALUE(EdgeGenFunction, edges_weight_function) 45 | 46 | void check_gen_function() { 47 | __check_nodes_weight_function(); 48 | __check_edges_weight_function(); 49 | } 50 | 51 | void check_nodes_weight_function() { 52 | __check_nodes_weight_function(); 53 | } 54 | 55 | void check_edges_weight_function() { 56 | __check_edges_weight_function(); 57 | } 58 | protected: 59 | 60 | template = 0> 61 | void __check_nodes_weight_function() { 62 | if (_nodes_weight_function == nullptr) { 63 | _msg::__fail_msg(_msg::_defl, "nodes weight generator function is nullptr, please set it."); 64 | } 65 | } 66 | 67 | template = 0> 68 | void __check_nodes_weight_function() {} 69 | 70 | template = 0> 71 | void __check_edges_weight_function() { 72 | if (_edges_weight_function == nullptr) { 73 | _msg::__fail_msg(_msg::_defl, "edges weight generator function is nullptr, please set it."); 74 | } 75 | } 76 | 77 | template = 0> 78 | void __check_edges_weight_function() {} 79 | }; 80 | 81 | } // namespace basic 82 | } // namespace rand_graph 83 | } // namespace generator 84 | 85 | #endif // !_SGPCET_GEN_FUNCTION_H_ 86 | -------------------------------------------------------------------------------- /src/graph/flower.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_FLOWER_H_ 2 | #define _SGPCET_FLOWER_H_ 3 | 4 | #ifndef _SGPCET_TREE_H_ 5 | #include "tree.h" 6 | #endif // !_SGPCET_TREE_H_ 7 | 8 | namespace generator { 9 | namespace rand_graph { 10 | namespace basic { 11 | template 12 | class Flower; 13 | 14 | template 15 | class FlowerGen : public BasicRandomFatherGen { 16 | protected: 17 | using Context = Flower; 18 | public: 19 | FlowerGen(Context& tree) : BasicRandomFatherGen(tree) {} 20 | protected: 21 | virtual void __random_father() override { 22 | for (int i = 1; i < this->_context.node_count(); i++) { 23 | this->__add_edge(this->_rank[0], this->_rank[i]); 24 | } 25 | } 26 | }; 27 | 28 | template 29 | class Flower : public _GenTree { 30 | protected: 31 | using _Self = Flower; 32 | _OUTPUT_FUNCTION(_Self) 33 | _DEF_GEN_FUNCTION 34 | public: 35 | template = 0> 36 | Flower(int node = 1, int begin_node = 1, bool is_rooted = false, int root = 1, 37 | NodeGenFunction nodes_weight_function = nullptr, 38 | EdgeGenFunction edges_weight_function = nullptr) : 39 | _GenTree(node, begin_node, is_rooted, root, 40 | nodes_weight_function, edges_weight_function) 41 | { 42 | _TREE_GRAPH_DEFAULT 43 | } 44 | 45 | template = 0> 46 | Flower(int node = 1, int begin_node = 1, bool is_rooted = false, int root = 1, 47 | EdgeGenFunction edges_weight_function = nullptr) : 48 | _GenTree(node, begin_node, is_rooted, root, edges_weight_function) 49 | { 50 | _TREE_GRAPH_DEFAULT 51 | } 52 | 53 | template = 0> 54 | Flower(int node = 1, int begin_node = 1, bool is_rooted = false, int root = 1, 55 | NodeGenFunction nodes_weight_function = nullptr) : 56 | _GenTree(node, begin_node, is_rooted, root, nodes_weight_function) 57 | { 58 | _TREE_GRAPH_DEFAULT 59 | } 60 | 61 | template = 0> 62 | Flower(int node = 1, int begin_node = 1, bool is_rooted = false, int root = 1) : 63 | _GenTree(node, begin_node, is_rooted, root) 64 | { 65 | _TREE_GRAPH_DEFAULT 66 | } 67 | _OUTPUT_FUNCTION_SETTING(_Self) 68 | protected: 69 | _DEFAULT_GRAPH_GEN_FUNC(Flower) 70 | }; 71 | } // namespace basic 72 | } // namespace rand_graph 73 | } // namespace generator 74 | 75 | #endif // !_SGPCET_FLOWER_H_ 76 | -------------------------------------------------------------------------------- /test/algorithm/TopologicalSort.h: -------------------------------------------------------------------------------- 1 | /* 2 | 最后修改: 3 | 20240705 4 | 测试环境: 5 | gcc11.2,c++11 6 | clang12.0,C++11 7 | msvc14.2,C++14 8 | */ 9 | #ifndef __OY_TOPOLOGICALSORT__ 10 | #define __OY_TOPOLOGICALSORT__ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace OY { 18 | namespace TOPO { 19 | using size_type = uint32_t; 20 | struct Solver { 21 | size_type m_vertex_cnt; 22 | std::vector m_deg, m_queue; 23 | Solver(size_type vertex_cnt) : m_vertex_cnt(vertex_cnt), m_deg(vertex_cnt), m_queue(vertex_cnt) {} 24 | template 25 | bool run(Traverser &&traverser) { 26 | size_type head = 0, tail = 0; 27 | for (size_type from = 0; from != m_vertex_cnt; from++) traverser(from, [&](size_type to) { m_deg[to]++; }); 28 | for (size_type i = 0; i != m_vertex_cnt; i++) 29 | if (!m_deg[i]) m_queue[tail++] = i; 30 | while (head != tail) traverser(m_queue[head++], [&](size_type to) {if(!--m_deg[to])m_queue[tail++]=to; }); 31 | return head == m_vertex_cnt; 32 | } 33 | template 34 | void trace(Callback &&call) const { 35 | for (size_type i = 0; i != m_vertex_cnt; i++) call(m_queue[i]); 36 | } 37 | }; 38 | struct Graph { 39 | struct raw_edge { 40 | size_type m_from, m_to; 41 | }; 42 | size_type m_vertex_cnt; 43 | mutable bool m_prepared; 44 | std::vector m_raw_edges; 45 | mutable std::vector m_starts, m_edges; 46 | void _prepare() const { 47 | m_prepared = true; 48 | m_starts.assign(m_vertex_cnt + 1, 0); 49 | for (auto &e : m_raw_edges) m_starts[e.m_from + 1]++; 50 | for (size_type i = 1; i != m_vertex_cnt + 1; i++) m_starts[i] += m_starts[i - 1]; 51 | auto cursor = m_starts; 52 | m_edges.resize(m_starts.back()); 53 | for (auto &e : m_raw_edges) m_edges[cursor[e.m_from]++] = e.m_to; 54 | } 55 | template 56 | void operator()(size_type from, Callback &&call) const { 57 | for (size_type cur = m_starts[from], end = m_starts[from + 1]; cur != end; cur++) call(m_edges[cur]); 58 | } 59 | Graph(size_type vertex_cnt = 0, size_type edge_cnt = 0) { resize(vertex_cnt, edge_cnt); } 60 | void resize(size_type vertex_cnt, size_type edge_cnt) { 61 | if (!(m_vertex_cnt = vertex_cnt)) return; 62 | m_prepared = false, m_raw_edges.clear(), m_raw_edges.reserve(edge_cnt); 63 | } 64 | void add_edge(size_type from, size_type to) { m_raw_edges.push_back({from, to}); } 65 | std::pair calc() const { 66 | if (!m_prepared) _prepare(); 67 | auto res = std::make_pair(Solver(m_vertex_cnt), false); 68 | res.second = res.first.run(*this); 69 | return res; 70 | } 71 | std::vector get_path() const { 72 | if (!m_prepared) _prepare(); 73 | std::vector res; 74 | Solver sol(m_vertex_cnt); 75 | if (!sol.run(*this)) return res; 76 | res.reserve(m_vertex_cnt); 77 | sol.trace([&](size_type i) { res.push_back(i); }); 78 | return res; 79 | } 80 | }; 81 | } 82 | }; 83 | 84 | #endif -------------------------------------------------------------------------------- /src/basic/enum.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_ENUM_H_ 2 | #define _SGPCET_ENUM_H_ 3 | 4 | namespace generator { 5 | namespace _enum { 6 | enum class Color { 7 | Red, 8 | Green, 9 | Yellow, 10 | Grey, 11 | Reset, 12 | Default = Reset, 13 | MaxColor 14 | }; 15 | 16 | constexpr int __color_index(Color color) { 17 | return static_cast(color); 18 | } 19 | 20 | enum class _JudgeState { 21 | _UNKNOWN, 22 | _AC, 23 | _WA, 24 | _ERROR = 3, 25 | _TLE = 4, 26 | _TLE_AC = 5, 27 | _TLE_WA = 6, 28 | _JUDGE_STATE_MAX 29 | }; 30 | 31 | constexpr int __state_index(_JudgeState state) { 32 | return static_cast(state); 33 | } 34 | 35 | inline _JudgeState& operator++(_JudgeState& s) { 36 | if (s != _JudgeState::_JUDGE_STATE_MAX) 37 | s = static_cast<_JudgeState>(static_cast(s) + 1); 38 | return s; 39 | } 40 | 41 | inline _JudgeState operator|(_JudgeState lhs, _JudgeState rhs) { 42 | return static_cast<_JudgeState>( 43 | static_cast(lhs) | static_cast(rhs) 44 | ); 45 | } 46 | 47 | inline _JudgeState& operator|=(_JudgeState& lhs, _JudgeState rhs) { 48 | lhs = lhs | rhs; 49 | return lhs; 50 | } 51 | 52 | bool __has_ac(_JudgeState state) { 53 | return state == _JudgeState::_AC || state == _JudgeState::_TLE_AC; 54 | } 55 | 56 | bool __has_wa(_JudgeState state) { 57 | return state == _JudgeState::_WA || state == _JudgeState::_TLE_WA; 58 | } 59 | 60 | bool __is_tle(_JudgeState state) { 61 | return state == _JudgeState::_TLE; 62 | } 63 | 64 | bool __has_tle(_JudgeState state) { 65 | return __is_tle(state) || state == _JudgeState::_TLE_AC || state == _JudgeState::_TLE_WA; 66 | } 67 | 68 | bool __is_combine_state(_JudgeState state) { 69 | return state == _JudgeState::_TLE_AC || state == _JudgeState::_TLE_WA; 70 | } 71 | 72 | bool __is_run_error(_JudgeState state) { 73 | return state == _JudgeState::_UNKNOWN || state == _JudgeState::_ERROR; 74 | } 75 | 76 | enum _End{ 77 | _IN, 78 | _OUT, 79 | _ANS, 80 | _LOG, 81 | _LOGC, 82 | _EXE, 83 | _VAL, 84 | _MAX_END 85 | }; 86 | 87 | enum _FuncProgramType { 88 | _GENERATOR, 89 | _CHECKER, 90 | _VALIDATOR, 91 | _RESULT, 92 | _OTHER 93 | }; 94 | 95 | enum _Stage { 96 | _INPUT, 97 | _OUTPUT, 98 | _VALID 99 | }; 100 | 101 | enum Checker{ 102 | lcmp, 103 | yesno, 104 | rcmp4, 105 | rcmp6, 106 | rcmp9, 107 | wcmp, 108 | MaxChecker 109 | }; 110 | 111 | enum CharType{ 112 | LowerLetter, 113 | UpperLetter, 114 | Letter, 115 | Number, 116 | LetterNumber, 117 | ZeroOne, 118 | MaxCharType 119 | }; 120 | 121 | enum TreeGenerator { 122 | RandomFather, 123 | Pruefer 124 | }; 125 | 126 | enum class LinkType { 127 | Direct, 128 | Increase, 129 | Shuffle, 130 | Dedupe 131 | }; 132 | 133 | using MergeType = LinkType; 134 | 135 | enum class TreeLinkType { 136 | Direct, 137 | Increase, 138 | Shuffle 139 | }; 140 | 141 | enum PointDirection { 142 | COUNTER_CLOCKWISE, 143 | CLOCKWISE, 144 | ONLINE_BACK, 145 | ONLINE_FRONT, 146 | ON_SEGMENT 147 | }; 148 | } // namespace _enum 149 | } // namespace generator 150 | 151 | #endif // !_SGPCET_ENUM_H_ 152 | -------------------------------------------------------------------------------- /test/algorithm/Bipartite.h: -------------------------------------------------------------------------------- 1 | /* 2 | 最后修改: 3 | 20240705 4 | 测试环境: 5 | gcc11.2,c++11 6 | clang12.0,C++11 7 | msvc14.2,C++14 8 | */ 9 | #ifndef __OY_BIPARTITE__ 10 | #define __OY_BIPARTITE__ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace OY { 18 | namespace Bipartite { 19 | using size_type = uint32_t; 20 | struct Solver { 21 | size_type m_vertex_cnt, m_color_cnt; 22 | bool m_ok; 23 | std::vector m_color; 24 | Solver(size_type vertex_cnt) : m_vertex_cnt(vertex_cnt), m_color_cnt(0), m_ok(true), m_color(vertex_cnt, -1) {} 25 | template 26 | bool run(Traverser &&traverser) { 27 | std::vector queue_buf(m_vertex_cnt); 28 | size_type *queue = queue_buf.data(); 29 | for (size_type i = 0; i != m_vertex_cnt; i++) 30 | if (!~m_color[i]) { 31 | size_type head = 0, tail = 0; 32 | m_color[i] = m_color_cnt, queue[tail++] = i; 33 | while (head != tail) { 34 | size_type from = queue[head++]; 35 | traverser(from, [&](size_type to) { 36 | if (!~m_color[to]) 37 | m_color[to] = m_color[from] ^ 1, queue[tail++] = to; 38 | else if (m_color[to] == m_color[from]) 39 | m_ok = false; 40 | }); 41 | if (!m_ok) return false; 42 | } 43 | m_color_cnt += 2; 44 | } 45 | return true; 46 | } 47 | bool in_same_group(size_type a, size_type b) const { return (m_color[a] | 1) == (m_color[b] | 1); } 48 | bool is_bipartite() const { return m_ok; } 49 | size_type query(size_type i) const { return m_color[i]; } 50 | }; 51 | struct Graph { 52 | struct raw_edge { 53 | size_type m_from, m_to; 54 | }; 55 | size_type m_vertex_cnt; 56 | mutable bool m_prepared; 57 | mutable std::vector m_starts; 58 | mutable std::vector m_edges; 59 | std::vector m_raw_edges; 60 | template 61 | void operator()(size_type from, Callback &&call) const { 62 | auto *first = m_edges.data() + m_starts[from], *last = m_edges.data() + m_starts[from + 1]; 63 | for (auto it = first; it != last; ++it) call(*it); 64 | } 65 | void _prepare() const { 66 | for (auto &e : m_raw_edges) { 67 | m_starts[e.m_from + 1]++; 68 | if (e.m_from != e.m_to) m_starts[e.m_to + 1]++; 69 | } 70 | for (size_type i = 1; i != m_vertex_cnt + 1; i++) m_starts[i] += m_starts[i - 1]; 71 | m_edges.resize(m_starts.back()); 72 | auto cursor = m_starts; 73 | for (auto &e : m_raw_edges) { 74 | m_edges[cursor[e.m_from]++] = e.m_to; 75 | if (e.m_from != e.m_to) m_edges[cursor[e.m_to]++] = e.m_from; 76 | } 77 | m_prepared = true; 78 | } 79 | Graph(size_type vertex_cnt = 0, size_type edge_cnt = 0) { resize(vertex_cnt, edge_cnt); } 80 | void resize(size_type vertex_cnt, size_type edge_cnt) { 81 | if (!(m_vertex_cnt = vertex_cnt)) return; 82 | m_prepared = false, m_raw_edges.clear(), m_raw_edges.reserve(edge_cnt); 83 | m_starts.assign(m_vertex_cnt + 1, {}); 84 | } 85 | void add_edge(size_type a, size_type b) { m_raw_edges.push_back({a, b}); } 86 | std::pair calc() const { 87 | if (!m_prepared) _prepare(); 88 | auto res = std::make_pair(Solver(m_vertex_cnt), false); 89 | res.second = res.first.run(*this); 90 | return res; 91 | } 92 | }; 93 | } 94 | } 95 | 96 | #endif -------------------------------------------------------------------------------- /test/test_numeric.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "test_basic.hpp" 3 | using namespace generator::all; 4 | 5 | TEST_CASE("numeric format", "[rand_numeric][format]") { 6 | init_gen(); 7 | // format int range 8 | auto r1 = __format_to_int_range("[10, 20]"); 9 | CHECK((r1.first == 10 && r1.second == 20)); 10 | auto r2 = __format_to_int_range("[1, 1e9]"); 11 | CHECK((r2.first == 1 && r2.second == 1000000000)); 12 | CHECK(std::is_same>::value); 13 | auto r3 = __format_to_int_range("[1, 1e9]"); 14 | CHECK(std::is_same>::value); 15 | auto r4 = __format_to_int_range("[1, 3.3)"); 16 | CHECK((r4.first == 1 && r4.second == 2)); 17 | 18 | // format double range 19 | using Catch::Matchers::WithinAbs; 20 | auto r5 = __format_to_double_range("[1.123,2.456)"); 21 | CHECK_THAT(r5.first, WithinAbs(1.123, 0.0001)); 22 | CHECK_THAT(r5.second, WithinAbs(2.456, 0.0001)); 23 | auto r6 = __format_to_double_range("(1.123,2.456]"); 24 | CHECK_THAT(r6.first, WithinAbs(1.124, 0.0001)); 25 | CHECK_THAT(r6.second, WithinAbs(2.4561, 0.00001)); 26 | auto r7 = __format_to_double_range("[1e-3, 2.34E-2)"); 27 | CHECK_THAT(r7.first, WithinAbs(0.001, 0.0001)); 28 | CHECK_THAT(r7.second, WithinAbs(0.0234, 0.00001)); 29 | } 30 | 31 | TEST_CASE("rand int testlib fail", "[rand_numeric][rand_int]") { 32 | init_gen(); 33 | 34 | long long ll_min = std::numeric_limits::min(); 35 | long long ll_max = std::numeric_limits::max(); 36 | unsigned int ui_max = std::numeric_limits::max(); 37 | unsigned long ul_min = std::numeric_limits::min(); 38 | unsigned long ul_max = std::numeric_limits::max(); 39 | unsigned long long ull_min = std::numeric_limits::min(); 40 | unsigned long long ull_max = std::numeric_limits::max(); 41 | unsigned long long ull_mid = (unsigned long long)ll_max + 1ULL; 42 | 43 | bool f1 = loop_check([&]() { 44 | long long x = rand_int(ll_min, ll_max); 45 | return x >= ll_min && x <= ll_max; 46 | }, 100); 47 | CHECK(f1); 48 | 49 | bool f2 = loop_check([&]() { 50 | unsigned int x = rand_int(ui_max); 51 | return x >= 0 && x < ui_max; 52 | }, 100); 53 | CHECK(f2); 54 | 55 | bool f3 = loop_check([&]() { 56 | unsigned long x = rand_int(ul_min, ul_max); 57 | return x >= ul_min && x <= ul_max; 58 | }, 100); 59 | CHECK(f3); 60 | bool f4 = loop_check([&]() { 61 | unsigned long long x = rand_int(ull_min, ull_max); 62 | return x >= ull_min && x <= ull_max; 63 | }, 100); 64 | CHECK(f4); 65 | 66 | bool f5 = loop_check([&]() { 67 | unsigned long long x = rand_int(ull_min, ull_mid); 68 | return x >= 0 && x < ull_mid; 69 | }, 100); 70 | CHECK(f5); 71 | } 72 | 73 | TEST_CASE("rand odd and even", "[rand_numeric][rand_odd][rand_even]") { 74 | init_gen(); 75 | _defl.set_log_same(false); // 循环转换范围的log不再重复打印 76 | bool f1 = loop_check([]() { return rand_odd(3) == 1; }, 100); // 随机[0,3)的奇数,肯定只有1 77 | CHECK(f1); 78 | bool f2 = loop_check([]() { return rand_even(2) == 0;}, 100); // 随机[0,2)的偶数,肯定只有0 79 | CHECK(f2); 80 | bool f3 = loop_check([]() { return rand_odd(-1, 0) == -1;}, 100); // 随机[-1,0]的奇数,肯定只有-1 81 | CHECK(f3); 82 | bool f4 = loop_check([]() { return rand_even(-1, 0) == 0;}, 100); // 随机[-1,0]的偶数,肯定只有0 83 | CHECK(f4); 84 | bool f5 = loop_check([]() { return rand_odd("[-1e9, 1e9]") % 2 != 0;}, 100); 85 | CHECK(f5); 86 | bool f6 = loop_check([]() { return rand_even("[-1e9, 1e9]") % 2 == 0;}, 100); 87 | CHECK(f6); 88 | } 89 | 90 | TEST_CASE("rand by probility", "[rand_numeric][rand_prob]") { 91 | init_gen(); 92 | std::map m; 93 | int sum = 0; 94 | for (int i = 'a'; i <='z'; i++) { 95 | int p = rand_int(1, 100); 96 | m[i] = p; 97 | sum += p; 98 | } 99 | std::vector v; 100 | v.resize(26); 101 | 102 | int rand_time = 1000000; 103 | for (int i = 0; i < rand_time; i++) { 104 | char c = rand_prob(m); 105 | v[c - 'a'] ++; 106 | } 107 | 108 | for (int i = 'a'; i <= 'z'; i++) { 109 | double p = (double)v[i - 'a'] / rand_time; 110 | double q = (double)m[i] / sum; 111 | CHECK(doubleCompare(p, q, 0.01)); // 1%的误差 112 | } 113 | } -------------------------------------------------------------------------------- /src/log/color.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_COLOR_H_ 2 | #define _SGPCET_COLOR_H_ 3 | 4 | #ifndef _SGPCET_SETTING_H_ 5 | #include "basic/setting.h" 6 | #endif // !_SGPCET_SETTING_H_ 7 | #ifndef _SGPCET_ENUM_H_ 8 | #include "basic/enum.h" 9 | #endif // !_SGPCET_ENUM_H_ 10 | 11 | namespace generator { 12 | 13 | namespace _msg { 14 | 15 | #ifdef ON_WINDOWS 16 | WORD _color_ansi[_enum::__color_index(_enum::Color::MaxColor)] = { 17 | FOREGROUND_RED, 18 | FOREGROUND_GREEN, 19 | FOREGROUND_GREEN | FOREGROUND_RED, 20 | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED, 21 | 0 // default 22 | }; 23 | #else 24 | std::string _color_ansi[_enum::__color_index(_enum::Color::MaxColor)] = { 25 | "\033[1;31m", 26 | "\033[32m", 27 | "\033[1;33m", 28 | "\033[0m", 29 | "\033[0m" 30 | }; 31 | #endif // ON_WINDOWS 32 | 33 | FILE *__get_std_stream(const std::ostream &stream) { 34 | if (&stream == &std::cout) 35 | return stdout; 36 | else if ((&stream == &std::cerr) || (&stream == &std::clog)) 37 | return stderr; 38 | 39 | return 0; 40 | } 41 | 42 | bool __is_atty(const std::ostream &stream) { 43 | FILE *std_stream = __get_std_stream(stream); 44 | 45 | if (!std_stream) return false; 46 | 47 | #ifdef ON_WINDOWS 48 | return _isatty(_fileno(std_stream)); 49 | #else 50 | return isatty(fileno(std_stream)); 51 | #endif // ON_WINDOWS 52 | } 53 | 54 | static int _colorize_index = std::ios_base::xalloc(); 55 | 56 | bool __is_colorized(std::ostream &stream) { 57 | return __is_atty(stream) || static_cast(stream.iword(_colorize_index)); 58 | } 59 | 60 | #ifdef ON_WINDOWS 61 | void __win_color(std::ostream &stream, _enum::Color color) { 62 | if (!__is_atty(stream)) return; 63 | HANDLE hTerminal = INVALID_HANDLE_VALUE; 64 | if (&stream == &std::cout) hTerminal = GetStdHandle(STD_OUTPUT_HANDLE); 65 | else if (&stream == &std::cerr) hTerminal = GetStdHandle(STD_ERROR_HANDLE); 66 | 67 | if (!_color_ansi[_enum::__color_index(_enum::Color::Default)]) { 68 | CONSOLE_SCREEN_BUFFER_INFO info; 69 | if (!GetConsoleScreenBufferInfo(hTerminal, &info)) 70 | _color_ansi[_enum::__color_index(_enum::Color::Default)] = _color_ansi[_enum::__color_index(_enum::Color::Grey)]; 71 | else 72 | _color_ansi[_enum::__color_index(_enum::Color::Default)] = info.wAttributes; 73 | } 74 | 75 | SetConsoleTextAttribute(hTerminal, _color_ansi[_enum::__color_index(color)]); 76 | } 77 | #endif // ON_WINDOWS 78 | 79 | std::ostream& __color(std::ostream &stream, _enum::Color color) { 80 | if (__is_colorized(stream)) { 81 | #ifdef ON_WINDOWS 82 | __win_color(stream, color); 83 | #else 84 | stream << _color_ansi[_enum::__color_index(color)]; 85 | #endif // ON_WINDOWS 86 | } 87 | return stream; 88 | } 89 | 90 | #define _COLOR_FUNC(func, color) \ 91 | std::ostream& func(std::ostream& stream) { \ 92 | return __color(stream, color); \ 93 | } 94 | 95 | _COLOR_FUNC(__red, _enum::Color::Red) 96 | _COLOR_FUNC(__green, _enum::Color::Green) 97 | _COLOR_FUNC(__yellow, _enum::Color::Yellow) 98 | _COLOR_FUNC(__color_reset, _enum::Color::Reset) 99 | _COLOR_FUNC(__color_default, _enum::Color::Default) 100 | 101 | #undef _COLOR_FUNC 102 | 103 | class _ColorMsg { 104 | protected: 105 | std::string msg_; 106 | _enum::Color color_; 107 | public: 108 | _ColorMsg(std::string msg, _enum::Color color = _enum::Color::Default) : msg_(msg), color_(color) {} 109 | friend std::ostream& operator<<(std::ostream& os, const _ColorMsg& color_msg) { 110 | __color(os, color_msg.color_); 111 | os << color_msg.msg_; 112 | os << __color_reset; 113 | return os; 114 | } 115 | }; 116 | 117 | _ColorMsg _warn("WARN", _enum::Color::Yellow); 118 | _ColorMsg _success("SUCCESS", _enum::Color::Green); 119 | _ColorMsg _fail("FAIL", _enum::Color::Red); 120 | _ColorMsg _error("ERROR", _enum::Color::Red); 121 | _ColorMsg _set_fail("SETTING FAIL", _enum::Color::Red); 122 | 123 | } // namespace _msg 124 | } 125 | 126 | #endif // !_SGPCET_COLOR_H_ 127 | -------------------------------------------------------------------------------- /src/geometry/point.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_POINT_H_ 2 | #define _SGPCET_POINT_H_ 3 | 4 | #ifndef _SGPCET_COORDINATE_H_ 5 | #include "coordinate.h" 6 | #endif //!_SGPCET_COORDINATE_H_ 7 | 8 | namespace generator { 9 | namespace rand_geometry { 10 | 11 | template ::value>::type> 12 | class _2Points; 13 | 14 | template ::value>::type> 15 | class Point : public Coordinate { 16 | protected: 17 | using _Self = Point; 18 | _OUTPUT_FUNCTION(_Self) 19 | 20 | public: 21 | Point() : Coordinate(0, 0) { 22 | _DEFAULT_OUTPUT 23 | } 24 | 25 | Point(T x, T y) : Coordinate(x, y) { 26 | _DEFAULT_OUTPUT 27 | } 28 | 29 | Point(const Point& p) : Coordinate(p) { 30 | _DEFAULT_OUTPUT 31 | } 32 | Point(Point&& p) noexcept : Coordinate(std::move(p)) { 33 | _DEFAULT_OUTPUT 34 | } 35 | Point& operator=(const Point& p) { 36 | if (this != &p) 37 | Coordinate::operator=(p); 38 | return *this; 39 | } 40 | Point& operator=(Point&& p) noexcept { 41 | if (this!= &p) 42 | Coordinate::operator=(std::move(p)); 43 | return *this; 44 | } 45 | Point(const _2Points& p) : Coordinate(p.end() - p.start()) { 46 | _DEFAULT_OUTPUT 47 | } 48 | 49 | Point operator+(const Point& b) const { return Point(this->_x + b._x, this->_y + b._y); } 50 | Point& operator+=(const Point& b) { 51 | this->_x += b._x; 52 | this->_y += b._y; 53 | return *this; 54 | } 55 | Point operator-(const Point& b) const { return Point(this->_x - b._x, this->_y - b._y); } 56 | Point& operator-=(const Point& b) { 57 | this->_x -= b._x; 58 | this->_y -= b._y; 59 | return *this; 60 | } 61 | T& operator[](int idx) { 62 | if (idx == 0) return this->_x; 63 | if (idx == 1) return this->_y; 64 | _msg::__fail_msg(_msg::_defl, "index is out of range."); 65 | } 66 | T& operator[](char c) { 67 | if (c == 'x' || c == 'X') return this->_x; 68 | if (c == 'y' || c == 'Y') return this->_y; 69 | _msg::__fail_msg(_msg::_defl, "index is out of range."); 70 | 71 | } 72 | T& operator[](std::string s) { 73 | if(s.empty()) _msg::__fail_msg(_msg::_defl,"index s is an empty string."); 74 | return this->operator[](s[0]); 75 | } 76 | bool operator==(const Point& p) const{ return this->_x == p._x && this->_y == p._y; } 77 | bool operator!=(const Point& p) const{ return !(*this == p); } 78 | bool operator<(const Point& p) const{ return this->_x < p._x || (this->_x == p._x && this->_y < p._y); } 79 | bool operator<=(const Point& p) const{ return *this < p || *this == p; } 80 | bool operator>(const Point& p) const { return !(*this <= p); } 81 | bool operator>=(const Point& p) const { return !(*this < p); } 82 | 83 | _ResultTypeT operator^(const Point& b) const{ 84 | _ResultTypeT x1 = this->x(); 85 | _ResultTypeT y1 = this->y(); 86 | _ResultTypeT x2 = b.x(); 87 | _ResultTypeT y2 = b.y(); 88 | return x1 * y2 - y1 * x2; 89 | } 90 | 91 | _ResultTypeT operator*(const Point& b) const{ 92 | _ResultTypeT x1 = this->x(); 93 | _ResultTypeT y1 = this->y(); 94 | _ResultTypeT x2 = b.x(); 95 | _ResultTypeT y2 = b.y(); 96 | return x1 * x2 + y1 * y2; 97 | } 98 | 99 | _GEOMETRY_IN_RAND_FUNC(RandomCoordinate) 100 | _OUTPUT_FUNCTION_SETTING(_Self) 101 | protected: 102 | void __rand(RandomCoordinate& c) { 103 | c.gen(); 104 | this->_x = c.x(); 105 | this->_y = c.y(); 106 | } 107 | }; 108 | 109 | _GEOMETRY_OUT_RAND_FUNC(rand_point, Point) 110 | } // namespace rand_geometry 111 | } // namespace generator 112 | #endif // !_SGPCET_POINT_H_ 113 | -------------------------------------------------------------------------------- /test/algorithm/DSU.h: -------------------------------------------------------------------------------- 1 | /* 2 | 最后修改: 3 | 20240331 4 | 测试环境: 5 | gcc11.2,c++11 6 | clang12.0,C++11 7 | msvc14.2,C++14 8 | */ 9 | #ifndef __OY_DISJOINTUNION__ 10 | #define __OY_DISJOINTUNION__ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace OY { 18 | namespace DSU { 19 | using size_type = uint32_t; 20 | template 21 | struct Table { 22 | mutable std::vector m_parent, m_group_size; 23 | size_type m_size, m_group_cnt; 24 | Table(size_type n = 0) { resize(n); } 25 | void resize(size_type n) { 26 | if (!(m_size = m_group_cnt = n)) return; 27 | m_parent.resize(m_size); 28 | std::iota(m_parent.begin(), m_parent.end(), 0); 29 | if constexpr (MaintainGroupSize) m_group_size.assign(m_size, 1); 30 | } 31 | size_type find(size_type i) const { return m_parent[i] == i ? i : m_parent[i] = find(m_parent[i]); } 32 | template 33 | size_type size(size_type i) const { 34 | static_assert(MaintainGroupSize, "MaintainGroupSize Must Be True"); 35 | if constexpr (IsHead) 36 | return m_group_size[i]; 37 | else 38 | return m_group_size[find(i)]; 39 | } 40 | void unite_to(size_type head_a, size_type head_b) { 41 | if (head_a == head_b) return; 42 | m_parent[head_a] = head_b; 43 | if constexpr (MaintainGroupSize) m_group_size[head_b] += m_group_size[head_a]; 44 | m_group_cnt--; 45 | } 46 | bool unite_by_size(size_type a, size_type b) { 47 | static_assert(MaintainGroupSize, "MaintainGroupSize Must Be True"); 48 | a = find(a), b = find(b); 49 | if (a == b) return false; 50 | if (m_group_size[a] > m_group_size[b]) std::swap(a, b); 51 | unite_to(a, b); 52 | return true; 53 | } 54 | bool unite_by_ID(size_type a, size_type b) { 55 | a = find(a), b = find(b); 56 | if (a == b) return false; 57 | if (a < b) std::swap(a, b); 58 | unite_to(a, b); 59 | return true; 60 | } 61 | bool in_same_group(size_type a, size_type b) const { return find(a) == find(b); } 62 | bool is_head(size_type i) const { return i == m_parent[i]; } 63 | size_type count() const { return m_group_cnt; } 64 | std::vector heads() const { 65 | std::vector ret; 66 | ret.reserve(m_group_cnt); 67 | for (size_type i = 0; i != m_size; i++) 68 | if (is_head(i)) ret.push_back(i); 69 | return ret; 70 | } 71 | std::vector> groups() const { 72 | if constexpr (MaintainGroupSize) { 73 | std::vector> ret(m_group_cnt); 74 | std::vector index(m_size); 75 | for (size_type i = 0, j = 0; i != m_size; i++) 76 | if (is_head(i)) ret[j].reserve(m_group_size[i]), index[i] = j++; 77 | for (size_type i = 0; i != m_size; i++) ret[index[find(i)]].push_back(i); 78 | return ret; 79 | } else { 80 | std::vector> ret(m_group_cnt); 81 | std::vector index(m_size), cnt(m_group_cnt); 82 | for (size_type i = 0, j = 0; i != m_size; i++) 83 | if (is_head(i)) index[i] = j++; 84 | for (size_type i = 0; i != m_size; i++) cnt[index[find(i)]]++; 85 | for (size_type i = 0; i != m_group_cnt; i++) ret[i].reserve(cnt[i]); 86 | for (size_type i = 0; i != m_size; i++) ret[index[find(i)]].push_back(i); 87 | return ret; 88 | } 89 | } 90 | }; 91 | template 92 | Ostream &operator<<(Ostream &out, const Table &x) { 93 | out << "["; 94 | for (size_type i = 0; i != x.m_size; i++) { 95 | if (i) out << ", "; 96 | out << x.m_parent[i]; 97 | } 98 | return out << "]"; 99 | } 100 | } 101 | template 102 | using DSUTable = DSU::Table; 103 | } 104 | 105 | #endif -------------------------------------------------------------------------------- /src/graph/cycle_graph.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_CYCLE_GRAPH_H_ 2 | #define _SGPCET_CYCLE_GRAPH_H_ 3 | 4 | #ifndef _SGPCET_GRAPH_H_ 5 | #include "graph.h" 6 | #endif // !_SGPCET_GRAPH_H_ 7 | 8 | namespace generator { 9 | namespace rand_graph { 10 | namespace basic { 11 | template 12 | class CycleGraph; 13 | 14 | template 15 | class CycleGraphGen : public BasicGraphGen { 16 | protected: 17 | using Context = CycleGraph; 18 | public: 19 | CycleGraphGen(Context& graph) : BasicGraphGen(graph) {} 20 | 21 | protected: 22 | virtual void __self_init() override { 23 | __init_edge_count(); 24 | } 25 | 26 | void __init_edge_count() { 27 | _CONTEXT_GET_REF(edge_count) 28 | _CONTEXT_GET(node_count) 29 | edge_count = node_count; 30 | } 31 | 32 | virtual void __judge_lower_limit() override { 33 | _CONTEXT_GET(node_count) 34 | if (node_count < 3) { 35 | _msg::__fail_msg(_msg::_defl, 36 | "node_count must greater than or equal to 3, ", 37 | tools::string_format("but found %d.", node_count)); 38 | } 39 | } 40 | 41 | virtual void __generate_graph() override { 42 | _CONTEXT_GET(node_count) 43 | std::vector p = rnd.perm(node_count); 44 | for (int i = 0; i < node_count; i++) { 45 | this->__add_edge(p[i], p[(i + 1) % node_count]); 46 | } 47 | } 48 | }; 49 | 50 | template 51 | class CycleGraph : public _GenGraph { 52 | protected: 53 | using _Self = CycleGraph; 54 | _OUTPUT_FUNCTION(_Self) 55 | _DEF_GEN_FUNCTION 56 | public: 57 | template = 0> 58 | CycleGraph(int node_count = 3, int begin_node = 1, 59 | NodeGenFunction nodes_weight_function = nullptr, 60 | EdgeGenFunction edges_weight_function = nullptr) : 61 | _GenGraph(node_count, node_count, begin_node, 62 | true, false, false, false, false, 63 | nodes_weight_function, edges_weight_function) 64 | { 65 | _TREE_GRAPH_DEFAULT 66 | } 67 | 68 | template = 0> 69 | CycleGraph(int node_count = 3, int begin_node = 1, 70 | EdgeGenFunction edges_weight_function = nullptr) : 71 | _GenGraph(node_count, node_count, begin_node, 72 | true, false, false, false, false, 73 | edges_weight_function) 74 | { 75 | _TREE_GRAPH_DEFAULT 76 | } 77 | 78 | template = 0> 79 | CycleGraph(int node_count = 3, int begin_node = 1, 80 | NodeGenFunction nodes_weight_function = nullptr) : 81 | _GenGraph(node_count, node_count, begin_node, 82 | true, false, false, false, false, 83 | nodes_weight_function) 84 | { 85 | _TREE_GRAPH_DEFAULT 86 | } 87 | 88 | template = 0> 89 | CycleGraph(int node_count = 3, int begin_node = 1) : 90 | _GenGraph(node_count, node_count, begin_node, 91 | true, false, false, false, false) 92 | { 93 | _TREE_GRAPH_DEFAULT 94 | } 95 | 96 | _DISABLE_CONNECT 97 | _DISABLE_MULTIPLY_EDGE 98 | _DISABLE_SELF_LOOP 99 | _DISABLE_EDGE_COUNT 100 | _OUTPUT_FUNCTION_SETTING(_Self) 101 | 102 | protected: 103 | _DEFAULT_GRAPH_GEN_FUNC(CycleGraph) 104 | }; 105 | } // namespace basic 106 | } // namespace rand_graph 107 | } // namespace generator 108 | 109 | #endif // !_SGPCET_CYCLE_GRAPH_H_ 110 | -------------------------------------------------------------------------------- /src/graph/wheel_graph.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_WHEEL_GRAPH_H_ 2 | #define _SGPCET_WHEEL_GRAPH_H_ 3 | 4 | #ifndef _SGPCET_GRAPH_H_ 5 | #include "graph.h" 6 | #endif // !_SGPCET_GRAPH_H_ 7 | 8 | namespace generator { 9 | namespace rand_graph { 10 | namespace basic { 11 | template 12 | class WheelGraph; 13 | 14 | template 15 | class WheelGraphGen : public BasicGraphGen { 16 | protected: 17 | using Context = WheelGraph; 18 | public: 19 | WheelGraphGen(Context& graph) : BasicGraphGen(graph) {} 20 | 21 | protected: 22 | virtual void __self_init() override { 23 | __init_edge_count(); 24 | } 25 | 26 | void __init_edge_count() { 27 | _CONTEXT_GET_REF(edge_count) 28 | _CONTEXT_GET(node_count) 29 | edge_count = 2 * node_count - 2; 30 | } 31 | 32 | virtual void __judge_lower_limit() override { 33 | _CONTEXT_GET(node_count) 34 | if (node_count < 4) { 35 | _msg::__fail_msg(_msg::_defl, 36 | "node_count must greater than or equal to 4, ", 37 | tools::string_format("but found %d.", node_count)); 38 | } 39 | } 40 | 41 | virtual void __generate_graph() override { 42 | _CONTEXT_GET(node_count) 43 | std::vector p = rnd.perm(node_count); 44 | for (int i = 0; i < node_count - 1; i++) { 45 | this->__add_edge(p[i], p[(i + 1) % (node_count - 1)]); 46 | this->__add_edge(p[i], p[node_count - 1]); 47 | } 48 | } 49 | }; 50 | 51 | template 52 | class WheelGraph : public _GenGraph { 53 | protected: 54 | using _Self = WheelGraph; 55 | _OUTPUT_FUNCTION(_Self) 56 | _DEF_GEN_FUNCTION 57 | public: 58 | template = 0> 59 | WheelGraph(int node_count = 4, int begin_node = 1, 60 | NodeGenFunction nodes_weight_function = nullptr, 61 | EdgeGenFunction edges_weight_function = nullptr) : 62 | _GenGraph(node_count, 2 * node_count - 2, begin_node, 63 | true, false, false, false, false, 64 | nodes_weight_function, edges_weight_function) 65 | { 66 | _TREE_GRAPH_DEFAULT 67 | } 68 | 69 | template = 0> 70 | WheelGraph(int node_count = 4, int begin_node = 1, 71 | EdgeGenFunction edges_weight_function = nullptr) : 72 | _GenGraph(node_count, 2 * node_count - 2, begin_node, 73 | true, false, false, false, false, 74 | edges_weight_function) 75 | { 76 | _TREE_GRAPH_DEFAULT 77 | } 78 | 79 | template = 0> 80 | WheelGraph(int node_count = 4, int begin_node = 1, 81 | NodeGenFunction nodes_weight_function = nullptr) : 82 | _GenGraph(node_count, 2 * node_count - 2, begin_node, 83 | true, false, false, false, false, 84 | nodes_weight_function) 85 | { 86 | _TREE_GRAPH_DEFAULT 87 | } 88 | 89 | template = 0> 90 | WheelGraph(int node_count = 4, int begin_node = 1) : 91 | _GenGraph(node_count, 2 * node_count - 2, begin_node, 92 | true, false, false, false, false) 93 | { 94 | _TREE_GRAPH_DEFAULT 95 | } 96 | 97 | _DISABLE_CONNECT 98 | _DISABLE_MULTIPLY_EDGE 99 | _DISABLE_SELF_LOOP 100 | _DISABLE_EDGE_COUNT 101 | _OUTPUT_FUNCTION_SETTING(_Self) 102 | 103 | protected: 104 | _DEFAULT_GRAPH_GEN_FUNC(WheelGraph) 105 | }; 106 | } // namespace basic 107 | } // namespace rand_graph 108 | } // namespace generator 109 | 110 | #endif // !_SGPCET_WHEEL_GRAPH_H_ 111 | -------------------------------------------------------------------------------- /src/io/io_reporter.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_IO_REPORTER_H_ 2 | #define _SGPCET_IO_REPORTER_H_ 3 | 4 | #ifndef _SGPCET_IO_INIT_H_ 5 | #include "io/io_init.h" 6 | #endif // !_SGPCET_IO_INIT_H_ 7 | 8 | namespace generator { 9 | namespace io { 10 | _msg::_ColorMsg _ac_color("AC", _enum::Color::Green); 11 | _msg::_ColorMsg _wa_color("WA", _enum::Color::Red); 12 | _msg::_ColorMsg _tle_color("TLE", _enum::Color::Yellow); 13 | _msg::_ColorMsg _run_error_color("RE/UNK", _enum::Color::Red); 14 | _msg::_ColorMsg _checker_return_color("checker return :", _enum::Color::Red); 15 | 16 | _msg::_ColorMsg __state_msg(_enum::_JudgeState state, bool consider_tle) { 17 | if (_enum::__is_run_error(state)) return _run_error_color; 18 | if (consider_tle && _enum::__has_tle(state)) return _tle_color; 19 | else if (_enum::__has_ac(state)) return _ac_color; 20 | else return _wa_color; 21 | } 22 | 23 | void __state_msg(_msg::OutStream &out, _enum::_JudgeState state) { 24 | out.print(__state_msg(state, true)); 25 | if (_enum::__is_combine_state(state)) { 26 | out.print("("); 27 | out.print(__state_msg(state, false)); 28 | out.print(")"); 29 | } 30 | } 31 | 32 | void __judge_msg(_msg::OutStream &out, _enum::_JudgeState state, int case_id, int runtime, const std::string &result) { 33 | out.print(tools::string_format("Testcase %d : ", case_id)); 34 | if (_enum::__is_run_error(state)) { 35 | out.print(_msg::_error); 36 | out.println(" ,meet some error,pleace check it or report."); 37 | return; 38 | } 39 | __state_msg(out, state); 40 | out.print(tools::string_format(" ,Runtime = %dms", runtime)); 41 | if (_enum::__is_tle(state)) out.print(" (killed)"); 42 | out.print("."); 43 | if (_enum::__has_wa(state)) { 44 | out.println(" ", _checker_return_color); 45 | out.print(" ", result); 46 | } 47 | out.println(); 48 | } 49 | 50 | const char* __stage_name(_enum::_Stage stage) { 51 | if (stage == _enum::_INPUT) return "Make input"; 52 | if (stage == _enum::_OUTPUT) return "Make output"; 53 | if(stage == _enum::_VALID) return "Check input"; 54 | return "UNKNOWN"; 55 | } 56 | 57 | Path __stage_file(_enum::_Stage stage, int x) { 58 | return stage == _enum::_OUTPUT ? __testcase_output_file_path(x) : __testcase_input_file_path(x); 59 | } 60 | 61 | void __report_iov_summary_logs(std::unordered_map& results, _enum::_Stage stage) { 62 | int count = 0; 63 | std::vector errors; 64 | for (auto result : results) { 65 | count++; 66 | if (!result.second) errors.emplace_back(result.first); 67 | } 68 | _msg::__info_msg(_msg::_defl, _msg::_ColorMsg("Summary", _enum::Color::Green), " :"); 69 | _msg::__info_msg(_msg::_defl, tools::string_format("%s files (success / all) : %d / %d.", __stage_name(stage), count - errors.size(), count)); 70 | if (errors.size()) { 71 | _msg::__info_msg(_msg::_defl, "Program meets errors in files :"); 72 | for (int i : errors) 73 | _msg::__info_msg(_msg::_defl, tools::string_format(" %s", __stage_file(stage, i).cname())); 74 | _msg::__info_msg(_msg::_defl, _msg::_ColorMsg("Please Check.", _enum::Color::Red)); 75 | } else { 76 | _msg::__info_msg(_msg::_defl, _msg::_ColorMsg("All Success.", _enum::Color::Green)); 77 | } 78 | _msg::__endl(_msg::_defl); 79 | } 80 | 81 | void __report_comapre_stream_logs(int case_count, _msg::OutStream& stream, std::vector& results_count) { 82 | _msg::__info_msg(stream, "Total results :"); 83 | int error_count = 0; 84 | for (_enum::_JudgeState state = _enum::_JudgeState::_UNKNOWN; state < _enum::_JudgeState::_JUDGE_STATE_MAX; ++state) { 85 | if (_enum::__is_run_error(state)) { 86 | error_count += results_count[_enum::__state_index(state)]; 87 | continue; 88 | } 89 | __state_msg(stream, state); 90 | _msg::__info_msg(stream, tools::string_format(" : %d / %d", results_count[_enum::__state_index(state)], case_count)); 91 | } 92 | __state_msg(stream, _enum::_JudgeState::_ERROR); 93 | _msg::__info_msg(stream, tools::string_format(" : %d / %d", error_count, case_count)); 94 | 95 | } 96 | 97 | void __report_compare_logs(int case_count, _msg::OutStream& log, std::vector& results_count) { 98 | __report_comapre_stream_logs(case_count, log, results_count); 99 | __report_comapre_stream_logs(case_count, _msg::_defl, results_count); 100 | _msg::__info_msg(_msg::_defl, tools::string_format("The report is in %s file.", log.path().c_str())); 101 | _msg::__endl(_msg::_defl); 102 | } 103 | } // namespace io 104 | } // namespace generator 105 | 106 | #endif // !_SGPCET_IO_REPORTER_H_ 107 | -------------------------------------------------------------------------------- /src/graph/height_tree.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_HEIGHT_TREE_H_ 2 | #define _SGPCET_HEIGHT_TREE_H_ 3 | 4 | #ifndef _SGPCET_TREE_H_ 5 | #include "tree.h" 6 | #endif // !_SGPCET_TREE_H_ 7 | 8 | namespace generator { 9 | namespace rand_graph { 10 | namespace basic { 11 | template 12 | class HeightTree; 13 | 14 | template 15 | class HeightTreeGen : public BasicRandomFatherGen { 16 | protected: 17 | using Context = HeightTree; 18 | public: 19 | HeightTreeGen(Context& tree) : BasicRandomFatherGen(tree) {} 20 | protected: 21 | virtual void __self_init() override { 22 | _CONTEXT_GET_REF(height) 23 | _CONTEXT_GET(node_count) 24 | if (height == -1) { 25 | height = rnd.next(node_count == 1 ? 1 : 2, node_count); 26 | } 27 | } 28 | 29 | virtual void __judge_self_limit() override{ 30 | _CONTEXT_GET(node_count) 31 | _CONTEXT_GET(height) 32 | if (height > node_count || (node_count > 1 && height <= 1) || height < 1) { 33 | _msg::__fail_msg(_msg::_defl, 34 | tools::string_format("limit of the height is [%d, %d], but found %d.", 35 | node_count == 1 ? 1 : 2, node_count, height)); 36 | } 37 | } 38 | 39 | virtual void __random_father() override { 40 | _CONTEXT_GET(height) 41 | _CONTEXT_GET(node_count) 42 | std::vector number(height, 1); 43 | int w = node_count - height; 44 | for (int i = 1; i <= w; i++) { 45 | number[rnd.next(1, height - 1)]++; 46 | } 47 | int l = 0, r = 0, k = 0; 48 | for (int i = 1; i < node_count; i++) { 49 | if (r + number[k] == i) { 50 | l = r; 51 | r += number[k]; 52 | k++; 53 | } 54 | int f = rnd.next(l, r - 1); 55 | this->__add_edge(this->_rank[f], this->_rank[i]); 56 | } 57 | } 58 | }; 59 | 60 | template 61 | class HeightTree : public _GenTree { 62 | protected: 63 | using _Self = HeightTree; 64 | _OUTPUT_FUNCTION(_Self) 65 | _DEF_GEN_FUNCTION 66 | int _height; 67 | public: 68 | template = 0> 69 | HeightTree(int node = 1, int begin_node = 1, int root = 1, int height = -1, 70 | NodeGenFunction nodes_weight_function = nullptr, 71 | EdgeGenFunction edges_weight_function = nullptr) : 72 | _GenTree(node, begin_node, true, root, 73 | nodes_weight_function, edges_weight_function), 74 | _height(height) 75 | { 76 | _TREE_GRAPH_DEFAULT 77 | } 78 | 79 | template = 0> 80 | HeightTree(int node = 1, int begin_node = 1, int root = 1, int height = -1, 81 | EdgeGenFunction edges_weight_function = nullptr) : 82 | _GenTree(node, begin_node, true, root, edges_weight_function), 83 | _height(height) 84 | { 85 | _TREE_GRAPH_DEFAULT 86 | } 87 | 88 | template = 0> 89 | HeightTree(int node = 1, int begin_node = 1, int root = 1, int height = -1, 90 | NodeGenFunction nodes_weight_function = nullptr) : 91 | _GenTree(node, begin_node, true, root, nodes_weight_function), 92 | _height(height) 93 | { 94 | _TREE_GRAPH_DEFAULT 95 | } 96 | 97 | template = 0> 98 | HeightTree(int node = 1, int begin_node = 1, int root = 1, int height = -1) : 99 | _GenTree(node, begin_node, true, root), 100 | _height(height) 101 | { 102 | _TREE_GRAPH_DEFAULT 103 | } 104 | _OUTPUT_FUNCTION_SETTING(_Self) 105 | 106 | _SET_GET_VALUE(int, height) 107 | _MUST_IS_ROOTED 108 | protected: 109 | _DEFAULT_GRAPH_GEN_FUNC(HeightTree) 110 | }; 111 | } // namespace basic 112 | } // namespace rand_graph 113 | } // namespace generator 114 | 115 | #endif // !_SGPCET_HEIGHT_TREE_H_ 116 | -------------------------------------------------------------------------------- /test/algorithm/VectorTree.h: -------------------------------------------------------------------------------- 1 | /* 2 | 最后修改: 3 | 20230922 4 | 测试环境: 5 | gcc11.2,c++11 6 | clang12.0,C++11 7 | msvc14.2,C++14 8 | */ 9 | #ifndef __OY_VECTORTREE__ 10 | #define __OY_VECTORTREE__ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace OY { 19 | namespace VectorTree { 20 | using size_type = uint32_t; 21 | struct Ignore { 22 | template 23 | void operator()(Args... args) const {} 24 | }; 25 | template 26 | struct Edge { 27 | size_type m_to; 28 | Tp m_dis; 29 | }; 30 | template <> 31 | struct Edge { 32 | size_type m_to; 33 | }; 34 | template 35 | struct Tree { 36 | std::vector>> m_adj; 37 | size_type m_root = -1, m_vertex_cnt; 38 | void _add(size_type a, size_type b) { m_adj[a].push_back({b}); } 39 | void _add(size_type a, size_type b, Tp dis) { m_adj[a].push_back({b, dis}); } 40 | template ()(0, 0)), bool>::value> 41 | typename std::conditional::type _tree_dp_vertex(size_type a, size_type p, PreWork &&pre_work, Report &&report, AfterWork &&after_work) const { 42 | if constexpr (!IsBool) 43 | pre_work(a, p); 44 | else if (!pre_work(a, p)) 45 | return false; 46 | do_for_each_adj_vertex(a, [&](size_type to) { 47 | if constexpr (IsBool) { 48 | if (to != p && _tree_dp_vertex(to, a, pre_work, report, after_work)) report(a, to); 49 | } else if (to != p) 50 | _tree_dp_vertex(to, a, pre_work, report, after_work), report(a, to); 51 | }); 52 | after_work(a); 53 | if constexpr (IsBool) return true; 54 | } 55 | template ()(0, 0, std::declval())), bool>::value> 56 | typename std::conditional::type _tree_dp_edge(size_type a, size_type p, Tp up_dis, PreWork &&pre_work, Report &&report, AfterWork &&after_work) const { 57 | if constexpr (!IsBool) 58 | pre_work(a, p, up_dis); 59 | else if (!pre_work(a, p, up_dis)) 60 | return false; 61 | do_for_each_adj_edge(a, [&](size_type to, Tp dis) { 62 | if constexpr (IsBool) { 63 | if (to != p && _tree_dp_edge(to, a, dis, pre_work, report, after_work)) report(a, to, dis); 64 | } else if (to != p) 65 | _tree_dp_edge(to, a, dis, pre_work, report, after_work), report(a, to, dis); 66 | }); 67 | after_work(a); 68 | if constexpr (IsBool) return true; 69 | } 70 | Tree(size_type vertex_cnt = 0) { resize(vertex_cnt); } 71 | void resize(size_type vertex_cnt) { 72 | m_root = -1; 73 | if (!(m_vertex_cnt = vertex_cnt)) return; 74 | m_adj.assign(m_vertex_cnt, std::vector>()); 75 | } 76 | void add_edge(size_type a, size_type b, Tp dis = Tp()) { 77 | if constexpr (std::is_same::value) 78 | _add(a, b), _add(b, a); 79 | else 80 | _add(a, b, dis), _add(b, a, dis); 81 | } 82 | void prepare() {} 83 | size_type vertex_cnt() const { return m_vertex_cnt; } 84 | void set_root(size_type root) { m_root = root; } 85 | template 86 | void do_for_each_adj_vertex(size_type a, Callback &&call) const { 87 | for (auto &adj : m_adj[a]) call(adj.m_to); 88 | } 89 | template 90 | void do_for_each_adj_edge(size_type a, Callback &&call) const { 91 | if constexpr (std::is_same::value) 92 | for (auto &adj : m_adj[a]) call(adj.m_to, 1); 93 | else 94 | for (auto &adj : m_adj[a]) call(adj.m_to, adj.m_dis); 95 | } 96 | template 97 | void tree_dp_vertex(size_type a, PreWork &&pre_work, Report &&report, AfterWork &&after_work) const { _tree_dp_vertex(a, -1, pre_work, report, after_work); } 98 | template 99 | void tree_dp_edge(size_type a, PreWork &&pre_work, Report &&report, AfterWork &&after_work) const { _tree_dp_edge(a, -1, {}, pre_work, report, after_work); } 100 | }; 101 | template 102 | Ostream &operator<<(Ostream &out, const Tree &tree) { // http://mshang.ca/syntree/ 103 | tree.tree_dp_vertex( 104 | ~tree.m_root ? tree.m_root : 0, [&](size_type a, size_type) { out << '[' << a; }, {}, [&](size_type) { out << ']'; }); 105 | return out; 106 | } 107 | } 108 | } 109 | 110 | #endif -------------------------------------------------------------------------------- /src/graph/tree.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_TREE_H_ 2 | #define _SGPCET_TREE_H_ 3 | 4 | #ifndef _SGPCET_GEN_TREE_H_ 5 | #include "gen_tree.h" 6 | #endif // !_SGPCET_GEN_TREE_H_ 7 | #ifndef _SGPCET_ENUM_H_ 8 | #include "basic/enum.h" 9 | #endif // !_SGPCET_ENUM_H_ 10 | 11 | 12 | namespace generator { 13 | namespace rand_graph { 14 | namespace basic { 15 | template 16 | class Tree; 17 | 18 | template 19 | class TreeGen : public BasicTreeGen { 20 | public: 21 | using Context = Tree; 22 | TreeGen(Context& tree) : BasicTreeGen(tree) {} 23 | }; 24 | 25 | template 26 | class RandomFatherGen : public BasicRandomFatherGen { 27 | protected: 28 | using Context = Tree; 29 | public: 30 | RandomFatherGen(Context& tree) : BasicRandomFatherGen(tree) {} 31 | }; 32 | 33 | template 34 | class PrueferGen : public BasicPrueferGen { 35 | protected: 36 | using Context = Tree; 37 | public: 38 | PrueferGen(Context& tree) : BasicPrueferGen(tree) {} 39 | }; 40 | 41 | template 42 | class Tree : public _GenTree { 43 | protected: 44 | using _Self = Tree; 45 | _OUTPUT_FUNCTION(_Self) 46 | _DEF_GEN_FUNCTION 47 | public: 48 | using _GenTree::set_tree_generator; 49 | public: 50 | template = 0> 51 | Tree( 52 | int node_count = 1, int begin_node = 1, bool is_rooted = false, int root = 1, 53 | NodeGenFunction nodes_weight_function = nullptr, 54 | EdgeGenFunction edges_weight_function = nullptr, 55 | _enum::TreeGenerator tree_generator = _enum::RandomFather) : 56 | _GenTree(node_count, begin_node, is_rooted, root, 57 | nodes_weight_function, edges_weight_function) 58 | { 59 | _DEFAULT_OUTPUT 60 | set_tree_generator(tree_generator); 61 | } 62 | 63 | template = 0> 64 | Tree( 65 | int node_count = 1, int begin_node = 1, bool is_rooted = false, int root = 1, 66 | EdgeGenFunction edges_weight_function = nullptr, 67 | _enum::TreeGenerator tree_generator = _enum::RandomFather) : 68 | _GenTree(node_count, begin_node, is_rooted, root, edges_weight_function) 69 | { 70 | _DEFAULT_OUTPUT 71 | set_tree_generator(tree_generator); 72 | } 73 | 74 | template = 0> 75 | Tree( 76 | int node_count = 1, int begin_node = 1, bool is_rooted = false, int root = 1, 77 | NodeGenFunction nodes_weight_function = nullptr, 78 | _enum::TreeGenerator tree_generator = _enum::RandomFather) : 79 | _GenTree(node_count, begin_node, is_rooted, root, nodes_weight_function) 80 | { 81 | _DEFAULT_OUTPUT 82 | set_tree_generator(tree_generator); 83 | } 84 | 85 | template = 0> 86 | Tree( 87 | int node_count = 1, int begin_node = 1, bool is_rooted = false, int root = 1, 88 | _enum::TreeGenerator tree_generator = _enum::RandomFather) : 89 | _GenTree(node_count, begin_node, is_rooted, root) 90 | { 91 | _DEFAULT_OUTPUT 92 | set_tree_generator(tree_generator); 93 | } 94 | 95 | void set_tree_generator(_enum::TreeGenerator tree_generator) { 96 | if (tree_generator == _enum::RandomFather) use_random_father(); 97 | else use_pruefer(); 98 | } 99 | void use_random_father() { 100 | this->__delete_generator(); 101 | this->_generator = new RandomFatherGen(*this); 102 | } 103 | void use_pruefer() { 104 | this->__delete_generator(); 105 | this->_generator = new PrueferGen(*this); 106 | } 107 | 108 | _OUTPUT_FUNCTION_SETTING(_Self) 109 | }; 110 | 111 | } // namespace basic 112 | } // namespace rand_graph 113 | } // namespace generator 114 | 115 | #endif // !_SGPCET_TREE_H_ 116 | -------------------------------------------------------------------------------- /src/graph/edge_weight.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_EDGE_WEIGHT_H_ 2 | #define _SGPCET_EDGE_WEIGHT_H_ 3 | 4 | #ifndef _SGPCET_ALL_TREE_GRAPH_H_ 5 | #include "all_tree_graph.h" 6 | #endif // !_SGPCET_ALL_TREE_GRAPH_H_ 7 | 8 | namespace generator { 9 | namespace rand_graph { 10 | namespace edge_weight { 11 | template 12 | using Edge = basic::_Edge; 13 | 14 | using NodeWeight = basic::_Node; 15 | 16 | using TreeGenerator = _enum::TreeGenerator; 17 | 18 | template 19 | using TreeGen = basic::TreeGen; 20 | 21 | template 22 | using RandomFatherGen = basic::RandomFatherGen; 23 | 24 | template 25 | using PrueferGen = basic::PrueferGen; 26 | 27 | template 28 | using Tree = basic::Tree; 29 | 30 | template 31 | using ChainGen = basic::ChainGen; 32 | 33 | template 34 | using Chain = basic::Chain; 35 | 36 | template 37 | using FlowerGen = basic::FlowerGen; 38 | 39 | template 40 | using Flower = basic::Flower; 41 | 42 | template 43 | using HeightTreeGen = basic::HeightTreeGen; 44 | 45 | template 46 | using HeightTree = basic::HeightTree; 47 | 48 | template 49 | using MaxDegreeTreeGen = basic::MaxDegreeTreeGen; 50 | 51 | template 52 | using MaxDegreeTree = basic::MaxDegreeTree; 53 | 54 | template 55 | using MaxSonTreeGen = basic::MaxSonTreeGen; 56 | 57 | template 58 | using MaxSonTree = basic::MaxSonTree; 59 | 60 | template 61 | using GraphGen = basic::GraphGen; 62 | 63 | template 64 | using Graph = basic::Graph; 65 | 66 | template 67 | using BipartiteGraphGen = basic::BipartiteGraphGen; 68 | 69 | template 70 | using BipartiteGraph = basic::BipartiteGraph; 71 | 72 | template 73 | using DAGGen = basic::DAGGen; 74 | 75 | template 76 | using DAG = basic::DAG; 77 | 78 | template 79 | using CycleGraphGen = basic::CycleGraphGen; 80 | 81 | template 82 | using CycleGraph = basic::CycleGraph; 83 | 84 | template 85 | using WheelGraphGen = basic::WheelGraphGen; 86 | 87 | template 88 | using WheelGraph = basic::WheelGraph; 89 | 90 | template 91 | using GridGraphGen = basic::GridGraphGen; 92 | 93 | template 94 | using GridGraph = basic::GridGraph; 95 | 96 | template 97 | using PseudoTreeGen = basic::PseudoTreeGen; 98 | 99 | template 100 | using PseudoTree = basic::PseudoTree; 101 | 102 | template 103 | using PseudoInTreeGen = basic::PseudoInTreeGen; 104 | 105 | template 106 | using PseudoInTree = basic::PseudoInTree; 107 | 108 | template 109 | using PseudoOutTreeGen = basic::PseudoOutTreeGen; 110 | 111 | template 112 | using PseudoOutTree = basic::PseudoOutTree; 113 | 114 | template 115 | using CactusGen = basic::CactusGen; 116 | 117 | template 118 | using Cactus = basic::Cactus; 119 | 120 | template 121 | using LinkGen = basic::LinkGen; 122 | 123 | template 124 | using Link = basic::Link; 125 | 126 | template 127 | using TreeLinkGen = basic::TreeLinkGen; 128 | 129 | template 130 | using TreeLink = basic::TreeLink; 131 | 132 | template 133 | using ForestGen = basic::ForestGen; 134 | 135 | template 136 | using Forest = basic::Forest; 137 | 138 | template 139 | using FlowerChainGen = basic::FlowerChainGen; 140 | 141 | template 142 | using FlowerChain = basic::FlowerChain; 143 | } // namespace edge_weight 144 | } // namespace rand_graph 145 | } // namespace generator 146 | 147 | #endif // !_SGPCET_EDGE_WEIGHT_H_ 148 | -------------------------------------------------------------------------------- /src/graph/node_weight.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_NODE_WEIGHT_H_ 2 | #define _SGPCET_NODE_WEIGHT_H_ 3 | 4 | #ifndef _SGPCET_ALL_TREE_GRAPH_H_ 5 | #include "all_tree_graph.h" 6 | #endif // !_SGPCET_ALL_TREE_GRAPH_H_ 7 | 8 | namespace generator { 9 | namespace rand_graph { 10 | namespace node_weight { 11 | using Edge = basic::_Edge; 12 | 13 | template 14 | using NodeWeight = basic::_Node; 15 | 16 | using TreeGenerator = _enum::TreeGenerator; 17 | 18 | template 19 | using TreeGen = basic::TreeGen; 20 | 21 | template 22 | using RandomFatherGen = basic::RandomFatherGen; 23 | 24 | template 25 | using PrueferGen = basic::PrueferGen; 26 | 27 | template 28 | using Tree = basic::Tree; 29 | 30 | template 31 | using ChainGen = basic::ChainGen; 32 | 33 | template 34 | using Chain = basic::Chain; 35 | 36 | template 37 | using FlowerGen = basic::FlowerGen; 38 | 39 | template 40 | using Flower = basic::Flower; 41 | 42 | template 43 | using HeightTreeGen = basic::HeightTreeGen; 44 | 45 | template 46 | using HeightTree = basic::HeightTree; 47 | 48 | template 49 | using MaxDegreeTreeGen = basic::MaxDegreeTreeGen; 50 | 51 | template 52 | using MaxDegreeTree = basic::MaxDegreeTree; 53 | 54 | template 55 | using MaxSonTreeGen = basic::MaxSonTreeGen; 56 | 57 | template 58 | using MaxSonTree = basic::MaxSonTree; 59 | 60 | template 61 | using GraphGen = basic::GraphGen; 62 | 63 | template 64 | using Graph = basic::Graph; 65 | 66 | template 67 | using BipartiteGraphGen = basic::BipartiteGraphGen; 68 | 69 | template 70 | using BipartiteGraph = basic::BipartiteGraph; 71 | 72 | template 73 | using DAGGen = basic::DAGGen; 74 | 75 | template 76 | using DAG = basic::DAG; 77 | 78 | template 79 | using CycleGraphGen = basic::CycleGraphGen; 80 | 81 | template 82 | using CycleGraph = basic::CycleGraph; 83 | 84 | template 85 | using WheelGraphGen = basic::WheelGraphGen; 86 | 87 | template 88 | using WheelGraph = basic::WheelGraph; 89 | 90 | template 91 | using GridGraphGen = basic::GridGraphGen; 92 | 93 | template 94 | using GridGraph = basic::GridGraph; 95 | 96 | template 97 | using PseudoTreeGen = basic::PseudoTreeGen; 98 | 99 | template 100 | using PseudoTree = basic::PseudoTree; 101 | 102 | template 103 | using PseudoInTreeGen = basic::PseudoInTreeGen; 104 | 105 | template 106 | using PseudoInTree = basic::PseudoInTree; 107 | 108 | template 109 | using PseudoOutTreeGen = basic::PseudoOutTreeGen; 110 | 111 | template 112 | using PseudoOutTree = basic::PseudoOutTree; 113 | 114 | template 115 | using CactusGen = basic::CactusGen; 116 | 117 | template 118 | using Cactus = basic::Cactus; 119 | 120 | template 121 | using LinkGen = basic::LinkGen; 122 | 123 | template 124 | using Link = basic::Link; 125 | 126 | template 127 | using TreeLinkGen = basic::TreeLinkGen; 128 | 129 | template 130 | using TreeLink = basic::TreeLink; 131 | 132 | template 133 | using ForestGen = basic::ForestGen; 134 | 135 | template 136 | using Forest = basic::Forest; 137 | 138 | template 139 | using FlowerChainGen = basic::FlowerChainGen; 140 | 141 | template 142 | using FlowerChain = basic::FlowerChain; 143 | } // namespace node_weight 144 | } // namespace rand_graph 145 | } // namespace generator 146 | 147 | #endif // !_SGPCET_NODE_WEIGHT_H_ 148 | -------------------------------------------------------------------------------- /src/graph/max_degree_tree.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_MAX_DEGREE_TREE_H_ 2 | #define _SGPCET_MAX_DEGREE_TREE_H_ 3 | 4 | #ifndef _SGPCET_TREE_H_ 5 | #include "tree.h" 6 | #endif // !_SGPCET_TREE_H_ 7 | 8 | namespace generator { 9 | namespace rand_graph { 10 | namespace basic { 11 | template 12 | class MaxDegreeTree; 13 | 14 | template 15 | class MaxDegreeTreeGen : public BasicPrueferGen { 16 | protected: 17 | using Context = MaxDegreeTree; 18 | public: 19 | MaxDegreeTreeGen(Context& tree) : BasicPrueferGen(tree) {} 20 | protected: 21 | virtual void __generate_pruefer() override { 22 | _CONTEXT_GET(node_count) 23 | _CONTEXT_GET(max_degree) 24 | std::vector times = rand_array::rand_sum(node_count, node_count - 2, 0, max_degree - 1); 25 | std::vector pruefer = rand_array::shuffle_index(times); 26 | this->__pruefer_decode(pruefer); 27 | } 28 | 29 | virtual void __self_init() override { 30 | _CONTEXT_GET_REF(max_degree) 31 | _CONTEXT_GET(node_count) 32 | if (max_degree == -1) { 33 | if (node_count == 1) max_degree = 0; 34 | else if (node_count == 2) max_degree = 1; 35 | else max_degree = rnd.next(2, node_count - 1); 36 | } 37 | } 38 | 39 | virtual void __judge_self_limit() override{ 40 | _CONTEXT_GET(node_count) 41 | _CONTEXT_GET(max_degree) 42 | if (max_degree > node_count - 1) { 43 | _msg::__warn_msg(_msg::_defl, 44 | tools::string_format("the max_degree limit %d is greater than node_count - 1(%d)", max_degree, node_count), 45 | ", equivalent to use Tree::use_pruefer()"); 46 | } 47 | int max_degree_limit = node_count == 1 ? 0 : (node_count == 2 ? 1 : 2); 48 | 49 | if (max_degree < max_degree_limit) { 50 | _msg::__fail_msg(_msg::_defl, 51 | tools::string_format("the max_degree limit of %s node's tree is greater than or equal to %d, but found %d.", 52 | node_count > 2 ? "3 or more" : std::to_string(node_count).c_str(), 53 | max_degree_limit, max_degree)); 54 | } 55 | } 56 | 57 | }; 58 | 59 | template 60 | class MaxDegreeTree : public _GenTree { 61 | protected: 62 | using _Self = MaxDegreeTree; 63 | _OUTPUT_FUNCTION(_Self) 64 | _DEF_GEN_FUNCTION 65 | int _max_degree; 66 | public: 67 | template = 0> 68 | MaxDegreeTree(int node = 1, int begin_node = 1, bool is_rooted = false, int root = 1, int max_degree = -1, 69 | NodeGenFunction nodes_weight_function = nullptr, 70 | EdgeGenFunction edges_weight_function = nullptr) : 71 | _GenTree(node, begin_node, is_rooted, root, 72 | nodes_weight_function, edges_weight_function), 73 | _max_degree(max_degree) 74 | { 75 | _TREE_GRAPH_DEFAULT 76 | } 77 | 78 | template = 0> 79 | MaxDegreeTree(int node = 1, int begin_node = 1, bool is_rooted = false, int root = 1, int max_degree = -1, 80 | EdgeGenFunction edges_weight_function = nullptr) : 81 | _GenTree(node, begin_node, is_rooted, root, edges_weight_function), 82 | _max_degree(max_degree) 83 | { 84 | _TREE_GRAPH_DEFAULT 85 | } 86 | 87 | template = 0> 88 | MaxDegreeTree(int node = 1, int begin_node = 1, bool is_rooted = false, int root = 1, int max_degree = -1, 89 | NodeGenFunction nodes_weight_function = nullptr) : 90 | _GenTree(node, begin_node, is_rooted, root, nodes_weight_function), 91 | _max_degree(max_degree) 92 | { 93 | _TREE_GRAPH_DEFAULT 94 | } 95 | 96 | template = 0> 97 | MaxDegreeTree(int node = 1, int begin_node = 1, bool is_rooted = false, int root = 1, int max_degree = -1) : 98 | _GenTree(node, begin_node, is_rooted, root), 99 | _max_degree(max_degree) 100 | { 101 | _TREE_GRAPH_DEFAULT 102 | } 103 | _OUTPUT_FUNCTION_SETTING(_Self) 104 | 105 | _SET_GET_VALUE(int, max_degree) 106 | protected: 107 | _DEFAULT_GRAPH_GEN_FUNC(MaxDegreeTree) 108 | }; 109 | } // namespace basic 110 | } // namespace rand_graph 111 | } // namespace generator 112 | 113 | #endif // !_SGPCET_MAX_DEGREE_TREE_H_ 114 | -------------------------------------------------------------------------------- /src/graph/dag.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_DAG_H_ 2 | #define _SGPCET_DAG_H_ 3 | 4 | #ifndef _SGPCET_GRAPH_H_ 5 | #include "graph.h" 6 | #endif // !_SGPCET_GRAPH_H_ 7 | 8 | namespace generator { 9 | namespace rand_graph { 10 | namespace basic { 11 | template 12 | class DAG; 13 | 14 | template 15 | class DAGGen : public BasicGraphGen { 16 | protected: 17 | using Context = DAG; 18 | std::vector _rank; 19 | public: 20 | DAGGen(Context& graph) : BasicGraphGen(graph) {} 21 | 22 | protected: 23 | virtual void __judge_upper_limit() override { 24 | _CONTEXT_GET(node_count) 25 | _CONTEXT_GET(edge_count) 26 | if (!_CONTEXT_V(multiply_edge)) { 27 | long long limit = (long long) node_count * (long long) (node_count - 1) / 2; 28 | if (edge_count > limit) { 29 | _msg::__fail_msg(_msg::_defl, 30 | tools::string_format("edge_count must less than or equal to %lld, but found %d.", 31 | limit, edge_count)); 32 | } 33 | } 34 | else { 35 | if (node_count == 1 && edge_count > 0) { 36 | _msg::__fail_msg(_msg::_defl, 37 | tools::string_format("edge_count must equal to 0, but found %d.", 38 | edge_count)); 39 | } 40 | 41 | } 42 | } 43 | 44 | virtual void __self_init() override{ 45 | _rank = rnd.perm(_CONTEXT_V(node_count), 0); 46 | } 47 | 48 | virtual void __generate_connect() override{ 49 | for (int i = 1; i < _CONTEXT_V(node_count); i++) { 50 | int f = rnd.next(i); 51 | this->__add_edge(_rank[f], _rank[i]); 52 | } 53 | } 54 | 55 | virtual _Edge __rand_edge() override { 56 | int u, v; 57 | _CONTEXT_GET(node_count) 58 | do { 59 | u = rnd.next(node_count); 60 | v = rnd.next(node_count); 61 | if (u > v) std::swap(u, v); 62 | u = _rank[u]; 63 | v = _rank[v]; 64 | } while (this->__judge_self_loop(u, v) || this->__judge_multiply_edge(u, v)); 65 | return this->__convert_edge(u, v); 66 | } 67 | }; 68 | 69 | template 70 | class DAG : public _GenGraph { 71 | protected: 72 | using _Self = DAG; 73 | _OUTPUT_FUNCTION(_Self) 74 | _DEF_GEN_FUNCTION 75 | public: 76 | template = 0> 77 | DAG(int node_count = 1, int edge_count = 0, int begin_node = 1, 78 | NodeGenFunction nodes_weight_function = nullptr, 79 | EdgeGenFunction edges_weight_function = nullptr) : 80 | _GenGraph(node_count, edge_count, begin_node, 81 | true, false, false, false, false, 82 | nodes_weight_function, edges_weight_function) 83 | { 84 | _TREE_GRAPH_DEFAULT 85 | } 86 | 87 | template = 0> 88 | DAG(int node_count = 1, int edge_count = 0, int begin_node = 1, 89 | EdgeGenFunction edges_weight_function = nullptr) : 90 | _GenGraph(node_count, edge_count, begin_node, 91 | true, false, false, false, false, 92 | edges_weight_function) 93 | { 94 | _TREE_GRAPH_DEFAULT 95 | } 96 | 97 | template = 0> 98 | DAG(int node_count = 1, int edge_count = 0, int begin_node = 1, 99 | NodeGenFunction nodes_weight_function = nullptr) : 100 | _GenGraph(node_count, edge_count, begin_node, 101 | true, false, false, false, false, 102 | nodes_weight_function) 103 | { 104 | _TREE_GRAPH_DEFAULT 105 | } 106 | 107 | template = 0> 108 | DAG(int node_count = 1, int edge_count = 0, int begin_node = 1) : 109 | _GenGraph(node_count, edge_count, begin_node, 110 | true, false, false, false, false) 111 | { 112 | _TREE_GRAPH_DEFAULT 113 | } 114 | 115 | _DISABLE_SELF_LOOP 116 | _DISABLE_DIRECTION 117 | _OUTPUT_FUNCTION_SETTING(_Self) 118 | protected: 119 | _DEFAULT_GRAPH_GEN_FUNC(DAG) 120 | }; 121 | } // namespace basic 122 | } // namespace rand_graph 123 | } // namespace generator 124 | 125 | #endif // !_SGPCET_DAG_H_ 126 | -------------------------------------------------------------------------------- /src/graph/max_son_tree.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_MAX_SON_TREE_H_ 2 | #define _SGPCET_MAX_SON_TREE_H_ 3 | 4 | #ifndef _SGPCET_TREE_H_ 5 | #include "tree.h" 6 | #endif // !_SGPCET_TREE_H_ 7 | 8 | namespace generator { 9 | namespace rand_graph { 10 | namespace basic { 11 | template 12 | class MaxSonTree; 13 | 14 | template 15 | class MaxSonTreeGen : public BasicPrueferGen { 16 | protected: 17 | using Context = MaxSonTree; 18 | public: 19 | MaxSonTreeGen(Context& tree) : BasicPrueferGen(tree) {} 20 | protected: 21 | virtual void __generate_pruefer() override { 22 | _CONTEXT_GET(max_son) 23 | _CONTEXT_GET(node_count) 24 | int max_degree = max_son + 1; 25 | std::vector times = rand_array::rand_sum(node_count, node_count - 2, 0, max_degree - 1); 26 | _CONTEXT_GET_REF(root) 27 | if (times[root] == max_degree - 1) { 28 | int p; 29 | do { 30 | p = rnd.next(0, node_count - 1); 31 | } while (p == root || times[p] == max_degree - 1); 32 | std::swap(times[root], times[p]); 33 | } 34 | std::vector pruefer = rand_array::shuffle_index(times); 35 | this->__pruefer_decode(pruefer); 36 | } 37 | 38 | virtual void __self_init() override { 39 | _CONTEXT_GET_REF(max_son) 40 | _CONTEXT_GET(node_count) 41 | if (max_son == -1) { 42 | if (node_count == 1) max_son = 0; 43 | else max_son = rnd.next(1, node_count - 1); 44 | } 45 | } 46 | 47 | virtual void __judge_self_limit() override{ 48 | _CONTEXT_GET(node_count) 49 | _CONTEXT_GET(max_son) 50 | if (max_son > node_count - 1) { 51 | _msg::__warn_msg(_msg::_defl, 52 | tools::string_format("the max_son limit %d is greater than node_count - 1(%d)", max_son, node_count), 53 | ", equivalent to use Tree::use_pruefer()"); 54 | } 55 | int max_son_limit = node_count == 1 ? 0 : 1; 56 | 57 | if (max_son < max_son_limit) { 58 | _msg::__fail_msg(_msg::_defl, 59 | tools::string_format("the max_son limit of %s node's tree is greater than or equal to %d, but found %d.", 60 | node_count > 1 ? "2 or more" : std::to_string(node_count).c_str(), 61 | max_son_limit, max_son)); 62 | } 63 | } 64 | 65 | }; 66 | 67 | template 68 | class MaxSonTree : public _GenTree { 69 | protected: 70 | using _Self = MaxSonTree; 71 | _OUTPUT_FUNCTION(_Self) 72 | _DEF_GEN_FUNCTION 73 | int _max_son; 74 | public: 75 | template = 0> 76 | MaxSonTree(int node = 1, int begin_node = 1, int root = 1, int max_son = -1, 77 | NodeGenFunction nodes_weight_function = nullptr, 78 | EdgeGenFunction edges_weight_function = nullptr) : 79 | _GenTree(node, begin_node, true, root, 80 | nodes_weight_function, edges_weight_function), 81 | _max_son(max_son) 82 | { 83 | _TREE_GRAPH_DEFAULT 84 | } 85 | 86 | template = 0> 87 | MaxSonTree(int node = 1, int begin_node = 1, int root = 1, int max_son = -1, 88 | EdgeGenFunction edges_weight_function = nullptr) : 89 | _GenTree(node, begin_node, true, root, edges_weight_function), 90 | _max_son(max_son) 91 | { 92 | _TREE_GRAPH_DEFAULT 93 | } 94 | 95 | template = 0> 96 | MaxSonTree(int node = 1, int begin_node = 1, int root = 1, int max_son = -1, 97 | NodeGenFunction nodes_weight_function = nullptr) : 98 | _GenTree(node, begin_node, true, root, nodes_weight_function), 99 | _max_son(max_son) 100 | { 101 | _TREE_GRAPH_DEFAULT 102 | } 103 | 104 | template = 0> 105 | MaxSonTree(int node = 1, int begin_node = 1, int root = 1, int max_son = -1) : 106 | _GenTree(node, begin_node, true, root), 107 | _max_son(max_son) 108 | { 109 | _TREE_GRAPH_DEFAULT 110 | } 111 | _OUTPUT_FUNCTION_SETTING(_Self) 112 | 113 | _SET_GET_VALUE(int, max_son) 114 | _MUST_IS_ROOTED 115 | protected: 116 | _DEFAULT_GRAPH_GEN_FUNC(MaxSonTree) 117 | }; 118 | } // namespace basic 119 | } // namespace rand_graph 120 | } // namespace generator 121 | 122 | #endif // !_SGPCET_MAX_SON_TREE_H_ 123 | -------------------------------------------------------------------------------- /src/geometry/points.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_POINTS_H_ 2 | #define _SGPCET_POINTS_H_ 3 | 4 | #ifndef _SGPCET_POINT_H_ 5 | #include "point.h" 6 | #endif //!_SGPCET_POINT_H_ 7 | 8 | namespace generator { 9 | namespace rand_geometry { 10 | 11 | template class GeoType, typename T> 12 | class BasicPolygonGen : public BasicGeometryGen { 13 | public: 14 | BasicPolygonGen(GeoType& context) : BasicGeometryGen(context) {} 15 | protected: 16 | virtual void __add_point(Point& p) { 17 | _CONTEXT_GET_REF(points); 18 | points.push_back(p); 19 | } 20 | 21 | virtual void __judge_self_limit() override { 22 | _CONTEXT_GET(node_count); 23 | if (node_count <= 0) { 24 | _msg::__fail_msg(_msg::_defl, 25 | tools::string_format("node_count should be greater than 0, but found %d.", node_count)); 26 | } 27 | if (node_count > _setting::node_limit) { 28 | _msg::__fail_msg(_msg::_defl, 29 | tools::string_format("node_count should be less than node_limit(%d), but found %d.", _setting::node_limit, node_count)); 30 | } 31 | if (!_CONTEXT_V(same_point)) __judge_max_node_count(); 32 | } 33 | 34 | template::value, int>::type = 0> 35 | void __judge_max_node_count() {} 36 | 37 | template::value, int>::type = 0> 38 | void __judge_max_node_count() { 39 | _CONTEXT_GET(node_count); 40 | _CONTEXT_GET(x_left_limit); 41 | _CONTEXT_GET(x_right_limit); 42 | _CONTEXT_GET(y_left_limit); 43 | _CONTEXT_GET(y_right_limit); 44 | T x_range = x_right_limit - x_left_limit + 1; 45 | T y_range = y_right_limit - y_left_limit + 1; 46 | if (x_range >= node_count || y_range >= node_count) return; 47 | T max_node_count = x_range * y_range; 48 | if (max_node_count >= node_count) return; 49 | _msg::__fail_msg(_msg::_defl, 50 | tools::string_format("node_count should be less than or equal to %d, but found %d.", max_node_count, node_count)); 51 | } 52 | }; 53 | 54 | template ::value>::type> 55 | class RandomPoints; 56 | 57 | template ::value>::type> 58 | class RandomPointsGen : public BasicPolygonGen { 59 | protected: 60 | std::set> _p; 61 | public: 62 | using Context = RandomPoints; 63 | using Super = BasicPolygonGen; 64 | RandomPointsGen(Context& points) : BasicPolygonGen(points) {} 65 | protected: 66 | virtual void __generate_geometry() override { 67 | _CONTEXT_GET(x_left_limit); 68 | _CONTEXT_GET(x_right_limit); 69 | _CONTEXT_GET(y_left_limit); 70 | _CONTEXT_GET(y_right_limit); 71 | _CONTEXT_GET(node_count); 72 | for (int i = 0; i < node_count; i++) { 73 | Point p; 74 | do { 75 | p = rand_point(x_left_limit, x_right_limit, y_left_limit, y_right_limit); 76 | } while (this->__judge_same_point(p)); 77 | this->__add_point(p); 78 | } 79 | } 80 | 81 | bool __judge_same_point(Point& p) { 82 | if (_CONTEXT_V(same_point)) return false; 83 | return _p.find(p) != _p.end(); 84 | } 85 | 86 | virtual void __add_point(Point& p) override { 87 | if (!_CONTEXT_V(same_point)) _p.insert(p); 88 | Super::__add_point(p); 89 | } 90 | virtual void __self_init() override { 91 | _CONTEXT_GET_REF(points); 92 | points.clear(); 93 | if (!_CONTEXT_V(same_point)) _p.clear(); 94 | } 95 | }; 96 | 97 | template 98 | class RandomPoints : public RandomCoordinate { 99 | protected: 100 | int _node_count; 101 | std::vector> _points; 102 | bool _same_point; 103 | bool _output_node_count; 104 | public: 105 | using _Self = RandomPoints; 106 | _OUTPUT_FUNCTION(_Self) 107 | public: 108 | RandomPoints(int node_count = 1, T x_left_limit = 0, T x_right_limit = 0, T y_left_limit = 0, T y_right_limit = 0) : 109 | RandomCoordinate(x_left_limit, x_right_limit, y_left_limit, y_right_limit), 110 | _node_count(node_count), _same_point(false), _output_node_count(true) 111 | { 112 | _GEOMETRY_DEFAULT 113 | } 114 | 115 | _SET_GET_VALUE(int, node_count); 116 | _SET_GET_VALUE(bool, output_node_count); 117 | _SET_GET_VALUE(bool, same_point); 118 | _SET_GET_VALUE(std::vector>, points); 119 | 120 | void default_output(std::ostream& os) const { 121 | if (_output_node_count) { 122 | os << _node_count << "\n"; 123 | } 124 | int points_count = 0; 125 | for (auto p : _points) { 126 | os << p; 127 | if (++points_count < _node_count) { 128 | os << "\n"; 129 | } 130 | } 131 | } 132 | 133 | _OUTPUT_FUNCTION_SETTING(_Self) 134 | protected: 135 | _DEFAULT_GEOMETRY_GEN_FUNC(RandomPoints) 136 | }; 137 | } // namespace rand_geometry 138 | } // namespace generator 139 | 140 | #endif //!_SGPCET_POINTS_H_ 141 | -------------------------------------------------------------------------------- /src/io/inputs_outputs.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_INPUTS_OUTPUTS_H_ 2 | #define _SGPCET_INPUTS_OUTPUTS_H_ 3 | 4 | #ifndef _SGPCET_IO_REPORTER_H_ 5 | #include "io_reporter.h" 6 | #endif // !_SGPCET_IO_REPORTER_H_ 7 | #ifndef _SGPCET_PROGRAM_H_ 8 | #include "program.h" 9 | #endif //!_SGPCET_PROGRAM_H_ 10 | 11 | namespace generator { 12 | namespace io { 13 | 14 | template 15 | typename std::enable_if::value, void>::type 16 | __make_inputs_impl(const std::vector& inputs, T program) { 17 | __check_program_valid(program); 18 | __create_directories(__testcases_folder()); 19 | std::unordered_map results; 20 | _msg::__info_msg(_msg::_defl, _msg::_ColorMsg("Generator(Inputs)", _enum::Color::Green)); 21 | for (int i : inputs) { 22 | Path input = __testcase_input_file_path(i); 23 | _msg::__info_msg(_msg::_defl, tools::string_format("Generating input : %s", input.cname())); 24 | ReturnState state = __run_program( 25 | __generator_program(program, i), _setting::_default_path, input, _setting::_default_path, 26 | _setting::time_limit_inf, _enum::_GENERATOR); 27 | results[i] = __is_success(state.exit_code); 28 | } 29 | __report_iov_summary_logs(results, _enum::_INPUT); 30 | } 31 | 32 | template 33 | typename std::enable_if::value, void>::type 34 | make_inputs(int start, int end, T program) { 35 | std::vector inputs; 36 | for (int i = start; i <= end; i++) inputs.emplace_back(i); 37 | __make_inputs_impl(inputs, program); 38 | } 39 | 40 | template 41 | typename std::enable_if::value, void>::type 42 | make_inputs(int index, T program) { 43 | __make_inputs_impl({index}, program); 44 | } 45 | 46 | std::vector __find_not_exist_inputs(int sum) { 47 | if (sum <= 0) _msg::__fail_msg(_msg::_defl, tools::string_format("The number of inputs must be a positive number, but found %d.", sum)); 48 | std::vector inputs; 49 | __create_directories(__testcases_folder()); 50 | for (int i = 1; sum; i++) { 51 | if (i > _setting::test_case_limit) { 52 | _msg::__warn_msg(_msg::_defl, tools::string_format("Testcases are over the test_case_limit(%d).", _setting::test_case_limit)); 53 | return inputs; 54 | } 55 | if (!__testcase_input_file_exists(i)) { 56 | sum--; 57 | inputs.emplace_back(i); 58 | } 59 | } 60 | return inputs; 61 | } 62 | 63 | template 64 | typename std::enable_if::value, void>::type 65 | fill_inputs(int sum, T program) { 66 | __make_inputs_impl(__find_not_exist_inputs(sum), program); 67 | } 68 | 69 | template 70 | typename std::enable_if::value, void>::type 71 | fill_inputs(T program) { 72 | __make_inputs_impl(__find_not_exist_inputs(1), program); 73 | } 74 | 75 | template 76 | typename std::enable_if::value, void>::type 77 | __make_outputs_impl(const std::vector& outputs, T program, int time_limit) { 78 | __check_program_valid(program); 79 | std::unordered_map results; 80 | _msg::__info_msg(_msg::_defl, _msg::_ColorMsg("Generator(Outputs)", _enum::Color::Green)); 81 | for (int i : outputs) { 82 | Path input = __testcase_input_file_path(i); 83 | Path output = __testcase_output_file_path(i); 84 | _msg::__info_msg(_msg::_defl, tools::string_format("Generating output : %s", output.cname())); 85 | ReturnState state = __run_program( 86 | __result_program(program), input, output, _setting::_default_path, time_limit, _enum::_RESULT); 87 | results[i] = __is_success(state.exit_code) && !__time_limit_exceed(state.time, time_limit); 88 | if (__is_error(state.exit_code)) _msg::__info_msg(_msg::_defl, _run_error_color); 89 | if (__time_limit_exceed(state.time, time_limit)) _msg::__info_msg(_msg::_defl, _tle_color, 90 | tools::string_format(" running time(%dms) is greater than the time limit(%dms).", state.time, time_limit)); 91 | } 92 | __report_iov_summary_logs(results, _enum::_OUTPUT); 93 | } 94 | 95 | template 96 | typename std::enable_if::value, void>::type 97 | make_outputs(int start, int end, T program, int time_limit = _setting::time_limit_inf) { 98 | std::vector outputs; 99 | for (int i = start; i <= end; i++) 100 | if (__testcase_input_file_exists(i)) outputs.emplace_back(i); 101 | __make_outputs_impl(outputs, program, time_limit); 102 | } 103 | 104 | template 105 | typename std::enable_if::value, void>::type 106 | make_outputs(int index, T program, int time_limit = _setting::time_limit_inf) { 107 | __make_outputs_impl({index}, program, time_limit); 108 | } 109 | 110 | template 111 | typename std::enable_if::value, void>::type 112 | fill_outputs(T program, bool cover_exist = true, int time_limit = _setting::time_limit_inf) { 113 | std::vector outputs; 114 | std::vector inputs = __get_all_inputs(); 115 | for (int i : inputs) { 116 | if (!cover_exist && __testcase_output_file_exists(i)) continue; 117 | outputs.emplace_back(i); 118 | } 119 | __make_outputs_impl(outputs, program, time_limit); 120 | } 121 | } // namespace io 122 | } // namespace generator 123 | 124 | #endif // !_SGPCET_INPUTS_OUTPUTS_H_ 125 | -------------------------------------------------------------------------------- /src/geometry/coordinate.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_COORDINATE_H_ 2 | #define _SGPCET_COORDINATE_H_ 3 | 4 | #ifndef _SGPCET_GEOMETRY_STRATEGY_H_ 5 | #include "geometry_strategy.h" 6 | #endif //!_SGPCET_GEOMETRY_STRATEGY_H_ 7 | #ifndef _SGPCET_NUMERIC_H_ 8 | #include "rand/numeric.h" 9 | #endif //!_SGPCET_NUMERIC_H_ 10 | #ifndef _SGPCET_RANGE_FORMAT_H_ 11 | #include "range_format.h" 12 | #endif //!_SGPCET_RANGE_FORMAT_H_ 13 | 14 | namespace generator { 15 | namespace rand_geometry { 16 | 17 | template::value>::type> 18 | class Coordinate { 19 | protected: 20 | T _x, _y; 21 | 22 | using _Self = Coordinate; 23 | _OUTPUT_FUNCTION(_Self) 24 | public: 25 | Coordinate(T x = 0, T y = 0) : _x(x), _y(y) { 26 | _DEFAULT_OUTPUT 27 | } 28 | 29 | Coordinate(const Coordinate& p) : _x(p._x), _y(p._y) { 30 | _DEFAULT_OUTPUT 31 | } 32 | 33 | Coordinate(Coordinate&& p) noexcept : _x(std::move(p._x)), _y(std::move(p._y)) { 34 | _DEFAULT_OUTPUT 35 | } 36 | 37 | Coordinate& operator=(const Coordinate& p) { 38 | if (this != &p) { 39 | _x = p._x; 40 | _y = p._y; 41 | } 42 | return *this; 43 | } 44 | 45 | Coordinate& operator=(Coordinate&& p) noexcept { 46 | if (this != &p) { 47 | _x = std::move(p._x); 48 | _y = std::move(p._y); 49 | } 50 | return *this; 51 | } 52 | 53 | _SET_GET_VALUE(T, x); 54 | _SET_GET_VALUE(T, y); 55 | 56 | void default_output(std::ostream& os) const { 57 | os << _x << " " << _y; 58 | } 59 | 60 | _OUTPUT_FUNCTION_SETTING(_Self) 61 | }; 62 | 63 | template::value>::type> 64 | class LimitRange { 65 | protected: 66 | T _x_left_limit, _x_right_limit; 67 | T _y_left_limit, _y_right_limit; 68 | public: 69 | LimitRange(T x_left_limit = 0, T x_right_limit = 0, T y_left_limit = 0, T y_right_limit = 0) : 70 | _x_left_limit(x_left_limit), _x_right_limit(x_right_limit), 71 | _y_left_limit(y_left_limit), _y_right_limit(y_right_limit) {} 72 | 73 | _SET_GET_VALUE(T, x_left_limit); 74 | _SET_GET_VALUE(T, x_right_limit); 75 | _SET_GET_VALUE(T, y_left_limit); 76 | _SET_GET_VALUE(T, y_right_limit); 77 | 78 | void set_x_limit(T left_limit, T right_limit) { 79 | _x_left_limit = left_limit; 80 | _x_right_limit = right_limit; 81 | } 82 | 83 | void set_x_limit(std::string format) { 84 | auto range = rand_numeric::__format_to_range(format); 85 | _x_left_limit = range.first; 86 | _x_right_limit = range.second; 87 | } 88 | 89 | void set_y_limit(T left_limit, T right_limit) { 90 | _y_left_limit = left_limit; 91 | _y_right_limit = right_limit; 92 | } 93 | 94 | void set_y_limit(std::string format) { 95 | auto range = rand_numeric::__format_to_range(format); 96 | _y_left_limit = range.first; 97 | _y_right_limit = range.second; 98 | } 99 | 100 | void set_xy_limit(T left, T right) { 101 | set_x_limit(left, right); 102 | set_y_limit(left, right); 103 | } 104 | 105 | void set_xy_limit(T x_left_limit, T x_right_limit, T y_left_limit, T y_right_limit) { 106 | set_x_limit(x_left_limit, x_right_limit); 107 | set_y_limit(y_left_limit, y_right_limit); 108 | } 109 | 110 | void set_xy_limit(std::string format) { 111 | auto range = __format_xy_range(format); 112 | set_x_limit(range.first); 113 | set_y_limit(range.second); 114 | } 115 | }; 116 | 117 | template::value>::type> 118 | class RandomCoordinate; 119 | 120 | template 121 | class RandomCoordinateGen : public BasicGeometryGen { 122 | public: 123 | using Context = RandomCoordinate; 124 | RandomCoordinateGen(Context& coordinate) : BasicGeometryGen(coordinate) {} 125 | protected: 126 | virtual void __generate_geometry() override { 127 | _CONTEXT_GET_REF(x); 128 | _CONTEXT_GET_REF(y); 129 | _CONTEXT_GET(x_left_limit); 130 | _CONTEXT_GET(x_right_limit); 131 | _CONTEXT_GET(y_left_limit); 132 | _CONTEXT_GET(y_right_limit); 133 | x = rand_numeric::rand_int(x_left_limit, x_right_limit); 134 | y = rand_numeric::rand_int(y_left_limit, y_right_limit); 135 | } 136 | 137 | }; 138 | 139 | template 140 | class RandomCoordinate : public Coordinate, public LimitRange, public _GeometryGenSwitch { 141 | protected: 142 | using _Self = RandomCoordinate; 143 | _OUTPUT_FUNCTION(_Self) 144 | public: 145 | RandomCoordinate(T x_left_limit = 0, T x_right_limit = 0, T y_left_limit = 0, T y_right_limit = 0) : 146 | Coordinate(), 147 | LimitRange(x_left_limit, x_right_limit, y_left_limit, y_right_limit), 148 | _GeometryGenSwitch() 149 | { 150 | _GEOMETRY_DEFAULT 151 | } 152 | 153 | void gen() { 154 | this->_generator->generate(); 155 | } 156 | 157 | _OUTPUT_FUNCTION_SETTING(_Self) 158 | protected: 159 | _DEFAULT_GEOMETRY_GEN_FUNC(RandomCoordinate) 160 | }; 161 | 162 | } // namespace rand_geometry 163 | } // namespace generator 164 | 165 | #endif // !_SGPCET_COORDINATE_H_ 166 | -------------------------------------------------------------------------------- /src/basic/macro.h: -------------------------------------------------------------------------------- 1 | #ifndef _SGPCET_MACRO_H_ 2 | #define _SGPCET_MACRO_H_ 3 | 4 | #include 5 | 6 | #ifndef _GET_VALUE_CONST 7 | #define _GET_VALUE_CONST(type, name) \ 8 | type name() const { return _##name; } 9 | #endif // !_GET_VALUE_CONST 10 | 11 | #ifndef _GET_VALUE_REF 12 | #define _GET_VALUE_REF(type, name) \ 13 | type& name##_ref() { return _##name; } 14 | #endif // !_GET_VALUE_REF 15 | 16 | #ifndef _GET_VALUE 17 | #define _GET_VALUE(type, name) \ 18 | _GET_VALUE_CONST(type, name) \ 19 | _GET_VALUE_REF(type, name) 20 | #endif // !_GET_VALUE 21 | 22 | 23 | #ifndef _SET_VALUE 24 | #define _SET_VALUE(type, name) \ 25 | void set_##name(type name) { _##name = name; } 26 | #endif // !_SET_VALUE 27 | 28 | #ifndef _SET_GET_VALUE 29 | #define _SET_GET_VALUE(type, name) \ 30 | _GET_VALUE(type, name) \ 31 | _SET_VALUE(type, name) 32 | #endif // !_SET_GET_VALUE 33 | 34 | #ifndef _OUTPUT_FUNCTION 35 | #define _OUTPUT_FUNCTION(_TYPE) \ 36 | typedef std::function OutputFunction; \ 37 | OutputFunction _output_function; 38 | #endif // !_OUTPUT_FUNCTION 39 | 40 | #ifndef _OUTPUT_FUNCTION_SETTING 41 | #define _OUTPUT_FUNCTION_SETTING(_TYPE) \ 42 | void set_output(OutputFunction func) { \ 43 | _output_function = func; \ 44 | } \ 45 | friend std::ostream& operator<<(std::ostream& os, const _TYPE& type) { \ 46 | type._output_function(os, type); \ 47 | return os; \ 48 | } \ 49 | void println() { \ 50 | std::cout << *this << std::endl; \ 51 | } \ 52 | void set_output_default() { \ 53 | _output_function = default_function(); \ 54 | } \ 55 | OutputFunction default_function() { \ 56 | OutputFunction func = \ 57 | [](std::ostream& os, const _TYPE& type) { \ 58 | type.default_output(os); \ 59 | }; \ 60 | return func; \ 61 | } 62 | #endif // !_OUTPUT_FUNCTION_SETTING 63 | 64 | #ifndef _DEF_GEN_FUNCTION 65 | #define _DEF_GEN_FUNCTION \ 66 | typedef std::function NodeGenFunction; \ 67 | typedef std::function EdgeGenFunction; 68 | #endif // !_DEF_GEN_FUNCTION 69 | 70 | #ifndef _CONTEXT_V 71 | #define _CONTEXT_V(name) \ 72 | this->_context.name() 73 | #endif // !_CONTEXT_V 74 | 75 | #ifndef _CONTEXT_V_REF 76 | #define _CONTEXT_V_REF(name) \ 77 | this->_context.name##_ref() 78 | #endif // !_CONTEXT_V_REF 79 | 80 | #ifndef _CONTEXT_GET 81 | #define _CONTEXT_GET(name) \ 82 | auto name = _CONTEXT_V(name); 83 | #endif // !_CONTEXT_GET 84 | 85 | #ifndef _CONTEXT_GET_REF 86 | #define _CONTEXT_GET_REF(name) \ 87 | auto& name = _CONTEXT_V_REF(name); 88 | #endif // !_CONTEXT_GET 89 | 90 | #ifndef _MUST_IS_ROOTED 91 | #define _MUST_IS_ROOTED \ 92 | void set_is_rooted(int is_rooted) = delete; 93 | #endif // !_MUST_IS_ROOTED 94 | 95 | #ifndef _DEFAULT_GRAPH_GEN_FUNC 96 | #define _DEFAULT_GRAPH_GEN_FUNC(name) \ 97 | void __default_generator() { \ 98 | this->_generator = new name##Gen(*this); \ 99 | } 100 | #endif // !_DEFAULT_GRAPH_GEN_FUNC 101 | 102 | #ifndef _DEFAULT_GEOMETRY_GEN_FUNC 103 | #define _DEFAULT_GEOMETRY_GEN_FUNC(name) \ 104 | void __default_generator() { \ 105 | this->_generator = new name##Gen(*this); \ 106 | } 107 | #endif //!_DEFAULT_GEOMETRY_GEN_FUN 108 | 109 | #ifndef _DEFAULT_OUTPUT 110 | #define _DEFAULT_OUTPUT \ 111 | _output_function = this->default_function(); 112 | #endif // !_DEFAULT_OUTPUT 113 | 114 | #ifndef _DEFAULT_GEN 115 | #define _DEFAULT_GEN \ 116 | __default_generator(); 117 | #endif // !_DEFAULT_GEN 118 | 119 | #ifndef _TREE_GRAPH_DEFAULT 120 | #define _TREE_GRAPH_DEFAULT \ 121 | _DEFAULT_OUTPUT \ 122 | _DEFAULT_GEN 123 | #endif // !_TREE_GRAPH_DEFAULT 124 | 125 | #ifndef _GEOMETRY_DEFAULT 126 | #define _GEOMETRY_DEFAULT \ 127 | _TREE_GRAPH_DEFAULT 128 | #endif //!_GEOMETRY_DEFAULT 129 | 130 | #ifndef _DISABLE_NODE_COUNT 131 | #define _DISABLE_NODE_COUNT \ 132 | void set_node_count(int node_count) = delete; 133 | #endif //!_DISABLE_NODE_COUNT 134 | 135 | #ifndef _DISABLE_EDGE_COUNT 136 | #define _DISABLE_EDGE_COUNT \ 137 | void set_edge_count(int edge_count) = delete; 138 | #endif // !_DISABLE_EDGE_COUNT 139 | 140 | #ifndef _DISABLE_DIRECTION 141 | #define _DISABLE_DIRECTION \ 142 | void set_direction(bool direction) = delete; 143 | #endif // !_DISABLE_DIRECTION 144 | 145 | #ifndef _DISABLE_MULTIPLY_EDGE 146 | #define _DISABLE_MULTIPLY_EDGE \ 147 | void set_multiply_edge(bool multiply_edge) = delete; 148 | #endif // !_DISABLE_MULTIPLY_EDGE 149 | 150 | #ifndef _DISABLE_SELF_LOOP 151 | #define _DISABLE_SELF_LOOP \ 152 | void set_self_loop(bool self_loop) = delete; 153 | #endif // !_DISABLE_SELF_LOOP 154 | 155 | #ifndef _DISABLE_CONNECT 156 | #define _DISABLE_CONNECT \ 157 | void set_connect(bool connect) = delete; 158 | #endif // !_DISABLE_CONNECT 159 | 160 | #ifndef _GEOMETRY_IN_RAND_FUNC 161 | #define _GEOMETRY_IN_RAND_FUNC(Gen) \ 162 | void rand(T x_left, T x_right, T y_left, T y_right) { \ 163 | Gen g; \ 164 | g.set_xy_limit(x_left, x_right, y_left, y_right); \ 165 | __rand(g); \ 166 | } \ 167 | void rand(T left, T right) { \ 168 | Gen g; \ 169 | g.set_xy_limit(left, right); \ 170 | __rand(g); \ 171 | } \ 172 | void rand(std::string format) { \ 173 | Gen g; \ 174 | g.set_xy_limit(format); \ 175 | __rand(g); \ 176 | } 177 | #endif //!_GEOMETRY_IN_RAND_FUNC 178 | 179 | #ifndef _GEOMETRY_OUT_RAND_FUNC 180 | #define _GEOMETRY_OUT_RAND_FUNC(FuncName, ReturnType) \ 181 | template ::value>::type> \ 182 | ReturnType FuncName(T x_left, T x_right, T y_left, T y_right) { \ 183 | ReturnType r; \ 184 | r.rand(x_left, x_right, y_left, y_right); \ 185 | return r; \ 186 | } \ 187 | template ::value>::type> \ 188 | ReturnType FuncName(T left, T right) { \ 189 | ReturnType r; \ 190 | r.rand(left, right); \ 191 | return r; \ 192 | } \ 193 | template ::value>::type> \ 194 | ReturnType FuncName(std::string format) { \ 195 | ReturnType r; \ 196 | r.rand(format); \ 197 | return r; \ 198 | } 199 | #endif //!_GEOMETRY_OUT_RAND_FUNC 200 | 201 | #ifndef _DISABLE_SAME_POINT 202 | #define _DISABLE_SAME_POINT \ 203 | void set_same_point(bool same_point) = delete; 204 | #endif //!_DISABLE_SAME_POINT 205 | 206 | #endif // !_SGPCET_MACRO_H_ 207 | --------------------------------------------------------------------------------