洛谷-P1536 村村通

  题目描述

某市调查城镇交通状况,得到现有城镇道路统计表。表中列出了每条道路直接连通的城镇。市政府 "村村通工程" 的目标是使全市任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要相互之间可达即可)。请你计算出最少还需要建设多少条道路?

  输入格式

输入包含若干组测试测试数据,每组测试数据的第一行给出两个用空格隔开的正整数,分别是城镇数目 n 和道路数目 m ;随后的 m 行对应 m 条道路,每行给出一对用空格隔开的正整数,分别是该条道路直接相连的两个城镇的编号。简单起见,城镇从 1到 n 编号。

注意:两个城市间可以有多条道路相通。

  输出格式

对于每组数据,对应一行一个整数。表示最少还需要建设的道路数目。

  输入输出样例

输入 #1

输出 #1复制

4 21 34 33 31 21 32 35 21 23 5999 00

102998

 

  说明/提示

数据规模与约定

对于 100% 的数据,保证 1≤n<1000 。

  题目分析

数据给出的信息有,城镇数和相连的城市,我们将相连的城市看作是一个集合。

如果,所有的城市都在一个集合,说明所有城市可以连通,若有两个集合,就需要修建一条公路使得这两个集合连通,由此可以推出:最后剩下n个集合需要修建 (n-1) 公路。

  可行代码

 

#include <iostream>
using namespace std;

void init(int n, int *fa) {
    for (int i = 1; i <= n; ++i)
        fa[i] = i;
    return;
}

int find(int x, int *fa) {
    if (x == fa[x])
        return x; // 如果x的父亲就是x那么就是找到了x的祖先节点
    return find(fa[x], fa); // 递归返回
}

void merge(int a, int b, int *fa) {
    a = find(a, fa);
    b = find(b, fa);
    if (a != b)
        fa[b] = a; // 如果两个元素不相等就让一个元素成为另一个元素的父节点
    return;
}

int main() {
    int village, RoadNum;
    while (cin >> village >> RoadNum) { // 多组输入
        if (!village)
            return 0;
        int road[village + 1];// 城镇编号从1开始
        init(village, road);
        while (RoadNum--) {
            int village1, village2;
            cin >> village1 >> village2;
            merge(village1, village2, road); // 合并所有有连接的城市
        }
        int sum = 0;
        for (int i = 1; i <= village; i++)// 检查剩余集合数
            if (i == find(i, road))
                sum++;
        cout << --sum << endl;
    }
    return 0;
}

 

End 感谢reader's阅读,洛谷题目链接:P1536 村村通 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

 

posted @ 2021-07-12 11:43  Kirk~~  阅读(165)  评论(0编辑  收藏  举报