diff --git a/作业/数据结构-金健/10213903403第六章作业.pdf b/作业/数据结构-金健/10213903403第六章作业.pdf new file mode 100644 index 0000000..7e17a49 Binary files /dev/null and b/作业/数据结构-金健/10213903403第六章作业.pdf differ diff --git a/作业/数据结构-金健/C++/第六章作业/CMakeLists.txt b/作业/数据结构-金健/C++/第六章作业/CMakeLists.txt new file mode 100644 index 0000000..9237078 --- /dev/null +++ b/作业/数据结构-金健/C++/第六章作业/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.26) +project(chapter6) + +set(CMAKE_CXX_STANDARD 23) + +add_executable(graph1 第六章作业1.cpp) +add_executable(graph2 第六章作业2.cpp) +SET(EXECUTABLE_OUTPUT_PATH R:/) + +set(CMAKE_CXX_FLAGS_RELEASE -fexec-charset=GBK) diff --git a/作业/数据结构-金健/C++/第六章作业/graph.hpp b/作业/数据结构-金健/C++/第六章作业/graph.hpp new file mode 100644 index 0000000..7d74acd --- /dev/null +++ b/作业/数据结构-金健/C++/第六章作业/graph.hpp @@ -0,0 +1,235 @@ +// +// Created by 423A35C7 on 2023-12-02. +// + +#ifndef GRAPH_H +#define GRAPH_H + +#include +#include +#include +#include +#include +#include +#include + +std::default_random_engine engine(time(nullptr)); + +class MergeFindSet { + using int_ptr = std::unique_ptr; + +public: + const int length; + + explicit MergeFindSet(const int n) + : length(n), elements(new int[n]) { + memset(this->elements.get(), -1, n * sizeof(int)); + } + + int find(const int index) { + return elements.get()[index] == -1 + ? index + : elements.get()[index] = find(elements.get()[index]); + } + + void merge(const int a, const int b) { + elements.get()[find(b)] = find(a); + } + + friend std::ostream& operator<<(std::ostream&out, const MergeFindSet&merge_find_set); + +private: + int_ptr elements; +}; + +std::ostream& operator<<(std::ostream&out, const MergeFindSet&merge_find_set) { + for (int i = 0; i < merge_find_set.length; ++i) { + out << merge_find_set.elements.get()[i] << "\t"; + } + return out; +} + + +/** + * \brief 打印高维类型 + * \tparam T 最内层的类型 + * \param high_dimension 高维指针,应为 int**, bool*** 等类似的类型 + * \param length 长度(每一维的长度都应一样) + * \param dimensino_num 维度 + */ +template +void print(void* high_dimension, const int length, const int dimensino_num = 1) { + void** temp = static_cast(high_dimension); + if (dimensino_num <= 1) { + for (int i = 0; i < length; ++i) { + std::cout << static_cast(high_dimension)[i] << "\t"; + } + std::cout << std::endl; + return; + } + for (int i = 0; i < length; ++i) { + print(temp[i], length, dimensino_num - 1); + } + std::cout << std::endl; +} + +class Graph { +public: + ~Graph() { + for (int i = 0; i < this->node_num; ++i) { + delete this->adjacency[i]; + } + delete this->adjacency; + for (int i = 0; i < this->node_num; ++i) { + delete this->incidence[i]; + } + delete this->incidence; + } + + explicit Graph(const int n) + : merge_find_set_(n) { + this->node_num = n; + std::uniform_int_distribution get_random(1, 100); + this->adjacency = new int *[n]; + this->incidence = new bool *[n]; + for (int i = 0; i < n; ++i) { + this->adjacency[i] = new int[n]; + this->incidence[i] = new bool[n]; + memset(this->incidence[i], 0, n * sizeof(bool)); + this->adjacency[i][i] = INT_MAX; + for (int j = 0; j < i; ++j) { + this->adjacency[i][j] = this->adjacency[j][i] = get_random(engine); + } + } + } + + void print_adjacency() const { + print(this->adjacency, this->node_num, 2); + } + + void print_incidence() const { + print(this->incidence, this->node_num, 2); + } + + void print_merge_find_set() { + std::cout << this->merge_find_set_ << std::endl; + } + + bool same_league(const int start, const int target) { + return this->merge_find_set_.find(start) == this->merge_find_set_.find(target); + } + + /** + * \brief 把目标城市所在联盟合并到起始城市所在联盟中 + * \param start 起始城市 + * \param target 目标城市 + */ + void merge(const int start, const int target) { + this->merge_find_set_.merge(start, target); + } + + /** + * \brief 开始记录关系矩阵是否被改变 + */ + void start_record_incidence() { + this->incidence_had_changed = false; + } + + /** + * \brief 停止记录并返回关系矩阵是否被改变 + * \return 关系矩阵是否被改变 + */ + bool stop_record_incidence() { + const bool temp = this->incidence_had_changed; + this->incidence_had_changed = false; + return temp; + } + + friend void one_turn(Graph*); + +protected: + /** + * \brief 邻接矩阵,表示任意两个城市之间的距离 + */ + int** adjacency; // 邻接矩阵 + /** + * \brief 城市数量 + */ + int node_num; + /** + * \brief 关系矩阵,任意两个城市之间如果有直接的公路则为true(是对称的,反自反的关系)(不一定满足传递性) + */ + bool** incidence; // 关系矩阵 + bool incidence_had_changed; + MergeFindSet merge_find_set_; +}; + + +class ComplexGraph : public Graph { +public: + ~ComplexGraph() { + // this->~Graph(); // 好像析构函数会自动调用,不需要手动调用 + delete this->alpha; + } + + explicit ComplexGraph(const int n) + : Graph(n) { + this->alpha = new int[n]; + std::uniform_int_distribution get_random(1, n / 2); + for (int i = 0; i < n; ++i) { + this->alpha[i] = get_random(engine); + } + } + + void print_alpha() { + // print(this->alpha, this->node_num, 1); + std::map> index_to_league; + for (int i = 0; i < this->node_num; ++i) { + int ancestor = this->merge_find_set_.find(i); + if (!index_to_league.contains(ancestor)) { + index_to_league.insert({ancestor, {}}); + } + index_to_league[ancestor].push_back(i); + } + for (const auto&[ancestor, child]: index_to_league) { + std::cout << "城市联盟 { "; + for (auto value: child) { + std::cout << value << " "; + } + std::cout << " } 的规模系数为 "; + std::cout << this->get_alpha(ancestor) << std::endl; + } + } + + void set_beta(const int beta) { + this->beta = beta; + } + + /** + * \brief 获取城市所在联盟的规模系数 + * \param index 城市序号 + * \return 城市所在联盟的规模系数 + */ + [[nodiscard]] int get_alpha(const int index) { + return this->alpha[this->merge_find_set_.find(index)]; + } + + /** + * \brief 城市所在联盟的规模系数增加1 + * \param index 城市序号 + */ + void increase_alpha(const int index) { + this->alpha[this->merge_find_set_.find(index)]++; + } + + friend void one_turn(ComplexGraph*); + +private: + /** + * \brief 每个城市的规模系数 + */ + int* alpha; + int beta = 0; // 限定系数 +}; + +#endif //GRAPH_H diff --git a/作业/数据结构-金健/C++/第六章作业/release/chapter6.zip b/作业/数据结构-金健/C++/第六章作业/release/chapter6.zip new file mode 100644 index 0000000..32cbcb2 Binary files /dev/null and b/作业/数据结构-金健/C++/第六章作业/release/chapter6.zip differ diff --git a/作业/数据结构-金健/C++/第六章作业/第六章作业1.cpp b/作业/数据结构-金健/C++/第六章作业/第六章作业1.cpp new file mode 100644 index 0000000..7137e27 --- /dev/null +++ b/作业/数据结构-金健/C++/第六章作业/第六章作业1.cpp @@ -0,0 +1,93 @@ +/* + * 初步了解后发现实现获取最短的距离有三种方法: + * 1. 使用标准库的merge或者inplace_merge,也就是归并排序; + * 2. 使用标准库的priority_queue,也就是优先级队列,也就是堆; + * 3. 使用标准库的multiset,也就是允许重复元素的集合(好像是用红黑树实现的) + * 由于这里每次只需要获取最短的路径,因此优先级队列可能是比较好的选择。 + * (但是空间复杂度可能会比较高,因为$n$个节点最多需要存$n^2$条边,而实际上 + * 最小生成树只要n-1条边就可以全部连通,优先级队列无法把长度过大的不可能选中的边排除) + * 但是优先级队列每次好像只能一个一个加,那还是用merge吧。 + */ + +/* + * 可以证明第二条规则无效,证明如下: + * 若A、B、C三个城市存在环,即A申请修建AB,B申请修建BC,C申请修建CA,那么根据每个城市 + * 只会选择与它最近的城市修建公路,则必定有AB < AC, BC < BA, CA < CB,因此 + * AB < AC < BC < AB,而AB < AB是不可能的,因此不会存在这样的情况; + * 同理,可以证明n个城市(n > 2)必定不存在环。 + */ + +/* + * 由于第二条规则无效,在第一题中,政府可以看做永远同意修建,因此,n个城市一轮后就会修建了 + * n条公路,而n-1条公路就能使城市全部连通,因此一轮结束后城市就已全部连通。 + */ + +#include +#include "graph.hpp" + +// 一轮 +void one_turn(Graph* graph) { + for (int start = 0; start < graph->node_num; ++start) { + int target; + while (true) { + int* target_ptr = std::min_element(graph->adjacency[start], + graph->adjacency[start] + graph->node_num); + // 如果最小的目标城市距离都是INT_MAX,则说明start与所有城市都已连通,则不再修建 + if (*target_ptr == INT_MAX) { + return; + } + target = target_ptr - graph->adjacency[start]; + // 如果在同一个城市联盟内,那么把这个目标城市排除,在剩下的目标城市中继续 + if (graph->same_league(start, target)) { + graph->adjacency[start][target] = INT_MAX; + continue; + } + // 如果已经修建过了,则换个目标城市 + if (graph->incidence[start][target]) { + continue; + } + // 不需要考虑三个或以上成环的情况 + break; + } + // 修建公路,即在关系矩阵上将相应的行列置为true + graph->incidence[start][target] = graph->incidence[target][start] = true; + // 把目标城市所在联盟合并到起始城市所在联盟中 + graph->merge(start, target); + } +} + +int main() { + int n; + std::cout << "输入城市的个数:"; + std::cin >> n; + auto graph = Graph(n); + std::cout << "初始的距离的邻接矩阵为:" << std::endl; + graph.print_adjacency(); + + one_turn(&graph); + std::cout << "第一轮后的关系矩阵如下:" << std::endl; + graph.print_incidence(); + std::cout << "并查集如下:" << std::endl; + graph.print_merge_find_set(); + std::cout << "可以看到,一轮后就已经全部连通。" << std::endl; + return 0; +} + +// 输入城市的个数:5 +// 初始的距离的邻接矩阵为: +// 2147483647 69 19 14 90 +// 69 2147483647 66 82 66 +// 19 66 2147483647 48 8 +// 14 82 48 2147483647 22 +// 90 66 8 22 2147483647 +// +// 第一轮后的关系矩阵如下: +// 0 0 0 1 0 +// 0 0 1 0 0 +// 0 1 0 0 1 +// 1 0 0 0 1 +// 0 0 1 1 0 +// +// 并查集如下: +// -1 0 0 0 0 +// 可以看到,一轮后就已经全部连通。 diff --git a/作业/数据结构-金健/C++/第六章作业/第六章作业2.cpp b/作业/数据结构-金健/C++/第六章作业/第六章作业2.cpp new file mode 100644 index 0000000..6106f11 --- /dev/null +++ b/作业/数据结构-金健/C++/第六章作业/第六章作业2.cpp @@ -0,0 +1,160 @@ +// +// Created by 423A35C7 on 2023-12-02. +// + +#include +#include "graph.hpp" +// 这次执行一轮后不一定结束了, +void one_turn(ComplexGraph* graph) { + for (int start = 0; start < graph->node_num; ++start) { + int target; + while (true) { + int* target_ptr = std::min_element(graph->adjacency[start], + graph->adjacency[start] + graph->node_num); + // 如果最小的目标城市距离都是INT_MAX,则说明start与所有城市都已连通,则不再修建 + if (*target_ptr == INT_MAX) { + return; + } + target = target_ptr - graph->adjacency[start]; + // 如果在同一个城市联盟内,那么把这个目标城市排除,在剩下的目标城市中继续 + if (graph->same_league(start, target)) { + graph->adjacency[start][target] = INT_MAX; + continue; + } + // 如果已经修建过了,则换个目标城市 + if (graph->incidence[start][target]) { + continue; + } + // 不需要考虑三个或以上成环的情况 + break; + } + const int start_alpha = graph->get_alpha(start); + const int target_alpha = graph->get_alpha(target); + // 当城市规模系数α到达限定系数β后,我们认为该 league + // 已经到达“稳定”,不再与任何其他城市修建公路。 + if (start_alpha >= graph->beta || target_alpha >= graph->beta) { + continue; + } + if (start_alpha < target_alpha) { + // 规模小于目标城市,则政府拒绝修建 + continue; + } + else if (start_alpha == target_alpha) { + // 若两个城市规模相等,则修建过后两座城市形成的 league 城市规模系数α增一 + graph->increase_alpha(start); + } + else if (start_alpha > target_alpha) { + // 若大于目标城市,则同意修建,规模系数不变 + ; + } + // 修建公路,即在关系矩阵上将相应的行列置为true + graph->incidence[start][target] = graph->incidence[target][start] = true; + graph->incidence_had_changed = true; // 保护字段为什么能直接访问? + // 把目标城市所在联盟合并到起始城市所在联盟中 + graph->merge(start, target); + } +} + +int main() { + int n, beta; + + std::cout << "输入城市的个数:"; + std::cin >> n; + auto graph = ComplexGraph(n); + std::cout << "初始的城市规模为:" << std::endl; + graph.print_alpha(); + std::cout << "请输入限定系数beta:"; + std::cin >> beta; + graph.set_beta(beta); + + std::cout << "初始的距离的邻接矩阵为:" << std::endl; + graph.print_adjacency(); + + for (int turn_num = 1; ; turn_num++) { + graph.start_record_incidence(); + one_turn(&graph); + // 当关系矩阵不再被改变,也就是说明不再修桥了,则说明达到稳定 + if (!graph.stop_record_incidence()) { + break; + } + std::cout << "第" << turn_num << "轮后的关系矩阵如下:" << std::endl; + graph.print_incidence(); + std::cout << "规模系数如下:" << std::endl; + graph.print_alpha(); + std::cout << "并查集如下:" << std::endl; + graph.print_merge_find_set(); + std::cout << std::endl; + } + std::cout << "已经达到稳定" << std::endl; + return 0; +} + +// 输入城市的个数:10 +// 初始的城市规模为: +// 城市联盟 { 0 } 的规模系数为 2 +// 城市联盟 { 1 } 的规模系数为 5 +// 城市联盟 { 2 } 的规模系数为 2 +// 城市联盟 { 3 } 的规模系数为 1 +// 城市联盟 { 4 } 的规模系数为 3 +// 城市联盟 { 5 } 的规模系数为 4 +// 城市联盟 { 6 } 的规模系数为 2 +// 城市联盟 { 7 } 的规模系数为 2 +// 城市联盟 { 8 } 的规模系数为 4 +// 城市联盟 { 9 } 的规模系数为 3 +// 请输入限定系数beta:5 +// 初始的距离的邻接矩阵为: +// 2147483647 63 39 34 97 93 35 42 68 29 +// 63 2147483647 11 100 82 48 31 2 33 58 +// 39 11 2147483647 85 100 27 47 97 86 91 +// 34 100 85 2147483647 15 32 16 77 84 29 +// 97 82 100 15 2147483647 4 53 63 54 29 +// 93 48 27 32 4 2147483647 25 85 86 58 +// 35 31 47 16 53 25 2147483647 97 27 88 +// 42 2 97 77 63 85 97 2147483647 61 91 +// 68 33 86 84 54 86 27 61 2147483647 66 +// 29 58 91 29 29 58 88 91 66 2147483647 +// +// 第1轮后的关系矩阵如下: +// 0 0 0 0 0 0 0 0 0 1 +// 0 0 0 0 0 0 0 0 0 0 +// 0 0 0 0 0 0 0 0 0 0 +// 0 0 0 0 0 0 1 0 0 0 +// 0 0 0 0 0 1 0 0 0 0 +// 0 0 0 0 1 0 0 0 0 0 +// 0 0 0 1 0 0 0 0 1 0 +// 0 0 0 0 0 0 0 0 0 0 +// 0 0 0 0 0 0 1 0 0 0 +// 1 0 0 0 0 0 0 0 0 0 +// +// 规模系数如下: +// 城市联盟 { 1 } 的规模系数为 5 +// 城市联盟 { 2 } 的规模系数为 2 +// 城市联盟 { 4 5 } 的规模系数为 4 +// 城市联盟 { 7 } 的规模系数为 2 +// 城市联盟 { 3 6 8 } 的规模系数为 4 +// 城市联盟 { 0 9 } 的规模系数为 3 +// 并查集如下: +// 9 -1 -1 8 5 -1 8 -1 -1 -1 +// +// 第2轮后的关系矩阵如下: +// 0 0 0 0 0 0 0 0 0 1 +// 0 0 0 0 0 0 0 0 0 0 +// 0 0 0 0 0 0 0 0 0 0 +// 0 0 0 0 1 0 1 0 0 0 +// 0 0 0 1 0 1 0 0 0 0 +// 0 0 0 0 1 0 0 0 0 0 +// 0 0 0 1 0 0 0 0 1 0 +// 0 0 0 0 0 0 0 0 0 0 +// 0 0 0 0 0 0 1 0 0 0 +// 1 0 0 0 0 0 0 0 0 0 +// +// 规模系数如下: +// 城市联盟 { 1 } 的规模系数为 5 +// 城市联盟 { 2 } 的规模系数为 2 +// 城市联盟 { 7 } 的规模系数为 2 +// 城市联盟 { 3 4 5 6 8 } 的规模系数为 5 +// 城市联盟 { 0 9 } 的规模系数为 3 +// 并查集如下: +// 9 -1 -1 8 8 8 8 -1 -1 -1 +// +// 已经达到稳定