您的位置:首页 > 理论基础 > 数据结构算法

数据结构实验:连通分量个数

2016-08-22 20:04 141 查看


题目描述

 在无向图中,如果从顶点vi到顶点vj有路径,则称vi和vj连通。如果图中任意两个顶点之间都连通,则称该图为连通图,
否则,称该图为非连通图,则其中的极大连通子图称为连通分量,这里所谓的极大是指子图中包含的顶点个数极大。
例如:一个无向图有5个顶点,1-3-5是连通的,2是连通的,4是连通的,则这个无向图有3个连通分量。
 


输入

 第一行是一个整数T,表示有T组测试样例(0 < T <= 50)。每个测试样例开始一行包括两个整数N,M,(0 < N <= 20,0 <= M <= 200)
分别代表N个顶点,和M条边。下面的M行,每行有两个整数u,v,顶点u和顶点v相连。


输出

 每行一个整数,连通分量个数。


示例输入

2
3 1
1 2
3 2
3 2
1 2



示例输出

2
1


提示

#include <iostream>

#include<cstdio>

#include<cstring>

#include<cstdlib>

using namespace std;

typedef struct arcnode

{

    int adj;

}arcnode,adjmatrix[200][200];

typedef struct

{

    adjmatrix a;

    int vn;

    int an;

}MG;

int create(MG &g,int n,int m)//生成邻接矩阵;

{

    int i,j;

    int v1,v2;

    g.vn=n;

    g.an=m;

    for(i=1;i<=g.vn;i++)

        for(j=1;j<=g.vn;j++)

         g.a[i][j].adj=0;

    for(i=1;i<=g.an;i++)

    {

        scanf("%d%d",&v1,&v2);

        g.a[v1][v2].adj=1;

        g.a[v2][v1]=g.a[v1][v2];

    }

    return 1;

}

int v[110];//标记图的顶点是否访问过;

void dfs(MG &g,int i)//深度优先搜索;

{

    int j;//j在函数内部,不然不能回溯;

    v[i]=1;

    for(j=1;j<=g.vn;j++)

        if(g.a[i][j].adj==1&&!v[j])

    {

        dfs(g,j);

    }

}

int i,count;//记录连通分量个数;

void dfs1(MG &g)//统计连通分量的个数

{

    //int i;//若不在函数内部不会回溯;

    for(i=1;i<=g.vn;i++)

        if(!v[i])

    {

        count++;

        dfs(g,i);

    }

}

int main()

{

    int t;

    MG g;

    scanf("%d",&t);

    while(t--)

    {

        count=0;

        memset(v,0,sizeof(v));//标记数组初始化;

        int n,m;

        scanf("%d%d",&n,&m);

        create(g,n,m);

        dfs1(g);

        printf("%d\n",count);

    }

    return 0;

}

#include <cstdio>
#define MAX 2000
using namespace std;

int pre[MAX+1];

void Initialize(int n) {		// 初始化各结点的 pre 为自身
for(int i=0; i<=n; ++i) {	// 相当于初始时每个结点为各自独立的集合
pre[i] = i;
}
}

int Find(int a) {				// 查找 a 所在集合的根结点 root
int root = a;				// root 初始化为其本身
while(pre[root] != root) {	// 当 root 的上级结点不是其本身
root = pre[root];		// 令 root 为它的上级结点,继续查找
}
while(pre[a] != root) {		// 再次遍历,路径压缩
int temp = pre[a];
pre[a] = root;			// 沿途结点直接指向到 root
a = temp;
}

return root;
}

void Join(int a, int b) {		// 将 a, b 结点所在的集合合并
int root_a = Find(a);		// 查找 a 所在集合的根结点
int root_b = Find(b);		// 查找 b 所在集合的根结点
if(root_a != root_b) {		// 如果 a, b 不在同一集合,则合并
if(root_a > root_b)		// 根结点下标大的集合并入下标小的集合
pre[root_a] = root_b;
else pre[root_b] = root_a;
}
}

int Count(int n) {				// 统计不相交集合的个数
int cnt = 0;				// 计数变量
for(int i=1; i<=n; ++i) {
int root = Find(i);		// 找到一个集合
if(root) {				// 如果是第一次找到此集合
cnt++;				// 计数
pre[root] = 0;		// 此根节点置0,防止重复
}
}

return cnt;
}

int main(int argc, char const *argv[]) {
int t, n, m, u, v;
scanf("%d", &t);
while(t--) {
scanf("%d %d", &n, &m);
Initialize(n);
while(m--) {
scanf("%d %d", &u, &v);
Join(u, v);
}
printf("%d\n", Count(n));
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: