一、连通图的相关概念
强连通图:有向图 G=(V,E) 中,若对于V中任意两个不同的顶点 x和 y,都存在从x到 y以及从 y到 x的路径,则称 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;
}