/*
 *  初步了解后发现实现获取最短的距离有三种方法：
 *  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
// 可以看到，一轮后就已经全部连通。
