94 lines
3.9 KiB
C++
94 lines
3.9 KiB
C++
|
/*
|
|||
|
* 初步了解后发现实现获取最短的距离有三种方法:
|
|||
|
* 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 <iostream>
|
|||
|
#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
|
|||
|
// 可以看到,一轮后就已经全部连通。
|