【练习】加边的无向图

加边的无向图

https://ac.nowcoder.com/acm/problem/14685


题目

题目描述:
给你一个 n 个点,m 条边的无向图,求至少要在这个的基础上加多少条无向边使得任意两个点可达~ 

输入描述:
第一行两个正整数 n 和 m 。
接下来的m行中,每行两个正整数 i 、 j ,表示点i与点j之间有一条无向道路。

输出描述:
输出一个整数,表示答案


解析

1)知识点

  1. 这道题是一道基础的dfs或并查集,一开始我是想这么说的。但是我发现题目吧dfs压死了。
  2. 因为dfs遍历标记用的空间在并查集的五倍,所以会MLE(代码依旧放下面了)。

2)看题目

  • 题目的意思就是让我们在已知一些边的情况下,把剩下的连成一张连通图

3)算法分析

  1. 这道题很简单,我们要连成一张连通图只要求这个图有几个联通分量就行了
  2. 因为两个联通分量之间只要加一条边,就可以互通了。
  3. 求联通分量当然就可以遍历搜索然后标记。也就可以用并查集。
  4. 并查集简单来说就是给一个节点找父亲,每个节点都有自己的父亲。单个节点自己就是自己的父亲。
  5. 然后祖宗(总会有个起源的祖宗)样就是一家人

4)算法操作

  1. 首先就是找祖宗(内含路径压缩):
    int find(int x) {
        return x == fa[x] ? x : fa[x] = find(fa[x]);
    }
    //fa[x] = find(fa[x])就是路径压缩,就是让父亲直接变成起源祖宗,以后查找就快了
  2. 然后就是合并在一起,就是让起源祖宗换人:
    void merge(int x, int y) {
        x = find(x);
        y = find(y);
        if (x != y) {
            fa[x] = y;
        }
    }

5)打代码

  1. 就先初始化节点父亲(为自己)。
  2. 然后开始结合。
  3. 接下来看有几个人祖宗是自己,就有几个连通块了。
  4. 减个一输出就好了。
  5. 下面全代码~


MLE代码

#include <iostream>
#include <cstring>
using namespace std;
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
//代码预处理区

const int MAX = 1e5 + 7;
int head[MAX], tot;
struct EDGE {
    int v, next;
} edge[MAX << 1];
int n, m;
int vis[MAX];
//全局变量区

void init();//前向星初始化
void add_edge(int u, int v);//前向星加边
void dfs(int u, int fa);//前向星dfs
//函数预定义区

int main() {
    IOS;
    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        int u, v; cin >> u >> v;
        add_edge(u, v);
        add_edge(v, u);
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        if (!vis[i]) {
            ans++;
            dfs(i, 0);
        }
    }
    cout << ans - 1 << endl;
    return 0;
}
void init() {
    memset(head, 0, sizeof head); tot = 0;
}
void add_edge(int u, int v) {
    tot++;
    edge[tot].v = v;
    edge[tot].next = head[u];
    head[u] = tot;
}
void dfs(int u, int fa) {
    vis[u] = 1;
    for (int i = head[u]; i; i = edge[i].next) {
        int v = edge[i].v;
        if (v == fa) continue;
        dfs(v, u);
    }
}
//函数区


AC代码

#include <iostream>
#include <cstring>
using namespace std;
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
//代码预处理区

const int MAX = 1e5 + 7;
int n, m;
int fa[MAX];
//全局变量区

int find(int x);
void merge(int x, int y);
//函数预定义区

int main() {
    IOS;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        fa[i] = i;
    }
    for (int i = 1; i <= m; i++) {
        int u, v; cin >> u >> v;
        merge(u, v);
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        if (i == find(i)) {
            ans++;
        }
    }
    cout << ans - 1 << endl;
    return 0;
}
int find(int x) {
    return x == fa[x] ? x : fa[x] = find(fa[x]);
}
void merge(int x, int y) {
    x = find(x);
    y = find(y);
    if (x != y) {
        fa[x] = y;
    }
}
//函数区
牛客算法竞赛入门课题解 文章被收录于专栏

憨憨的专栏

全部评论

相关推荐

喜欢走神的孤勇者练习时长两年半:爱华,信华,等华,黑华
点赞 评论 收藏
分享
10-28 14:42
门头沟学院 Java
watermelon1124:因为嵌入式炸了
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务