连通图与并查集

一、连通图的相关概念

连通分量无向图 G的一个极大连通子图称为 G的一个连通分量(或连通分支)。连通图只有一个连通分量,即其自身;非连通的无向图有多个连通分量。
强连通图有向图 G=(V,E) 中,若对于V中任意两个不同的顶点 x和 y,都存在从x到 y以及从 y到 x的路径,则称 G是强连通图。相应地有强连通分量的概念。强连通图只有一个强连通分量,即是其自身;非强连通的有向图有多个强连分量。
单向连通图:设G=<V,E>是有向图,如果u->v意味着图G至多包含一条从u到v的简单路径,则图G为单连通图。
弱连通图:将有向图的所有的有向边替换为无向边,所得到的图称为原图的基图。如果一个有向图的基图是连通图,则有向图是弱连通图。
初级通路:通路中所有的顶点互不相同。初级通路必为简单通路,但反之不真。
二、并查集
并查集是解决连通图类问题常用的方法。例如,像畅通工程这种题,问还需要修几条路,实质就是求有几个连通分支。
并查集由一个整数型的数组和两个函数构成。
int pre[1000];
int visit[1000];

int find(int a) {
    if (a==pre[a]) {
        return a;
    }
    
    return find(pre[a]);
}

void join(int a, int b) {
    int prea = find(a);
    int preb = find(b);
    if (prea != preb) {
        pre[preb] = prea;
    }
}

数组pre[]记录了每个点的前导点是什么。
find()函数为查找根节点的函数。最后有几个根结点,就有几个连通域。
三、acm例题

1908: 连通图

题目描述

给定一个无向图和其中的所有边,判断这个图是否所有顶点都是连通的。

输入

每组数据的第一行是两个整数 n 和 m(0<=n<=1000)。n 表示图的顶点数目,m 表示图中边的数目。如果 n 为 0 表示输入结束。随后有 m 行数据,每行有两个值 x 和 y(0<x, y <=n),表示顶点 x 和 y 相连,顶点的编号从 1 开始计算。输入不保证这些边是否重复。

输出

对于每组输入数据,如果所有顶点都是连通的,输出"YES",否则输出"NO"。

样例输入

4 3
4 3
1 2
1 3
5 7
3 5
2 3
1 3
3 2
2 5
3 4
4 1
7 3
6 2
3 1
5 6
0 0

样例输出

YES
YES
NO

#include <iostream>
using namespace std;

int pre[1000];
int visit[1000];

int find(int a) {
    if (a==pre[a]) {
        return a;
    }
    
    return find(pre[a]);
}

void join(int a, int b) {
    int prea = find(a);
    int preb = find(b);
    if (prea != preb) {
        pre[preb] = prea;
    }
}

int main(int argc, const char * argv[]) {
    while (true) {
        int m,n;
        cin >> n >> m;
        if (n==0) {
            break;
        }
        
        for (int i=1; i<=n; i++) {
            pre[i] = i;
            visit[i] = 0;
        }
        
        for (int i=1; i<=m; i++) {
            int a,b;
            cin >> a >> b;
            join(a, b);
        }
        
        int count=0;
        for (int i=1; i<=n; i++) {
            visit[find(i)]=1;
        }
        
        for (int i=1; i<=n; i++) {
            if (visit[i]==1) {
                count++;
            }
        }
        
        if (count==1) {
            cout << "YES" << endl;
        } else if (count > 1) {
            cout << "NO" << endl;
        }
        
        
    }
    
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值