联通块是指给定n个点,输入a,b(1<=a,b<=n),然后将a,b连接,凡是连接在一起的所有数就是一个联通块;

题意:第一行输入n,m,分别表示有n个数,有输入m对连接点,以下将要输入m行(输入数据到文件截止);

输出:第一行要求输出联通块的个数,并在第二行分别输出每个联通块中点的数量,每个数之间以一个空格隔开。

样例 1
5 3
1 4
2 5
3 5
输出:2
2 3
样列2

9 8
1 2
2 3
3 4
3 7
4 5
4 6
7 8
7 9
输出:

1
9

如果不明白的话可以画图试试,最多花半个小时,要是早这样不知道能省下多少个半小时呢;

此题可以利用并查集求解:
首先可以将N个点看成独立的联通块,然后每个每个独立的联通块都有一个节点,然后每次连接两个点,就将它们的节点加在一起;
代码如下:

 #include<iostream>
#include<cstring>
using namespace std;
const int maxn=;
int p[maxn];//作为每个独立的点
int sum[maxn];//每个节点下面连接的点
int find(int x)
{
if(x==p[x])return x;
return p[x]=find(p[x]);//压缩路径
}
int main()
{
int n,m;
while(cin>>n>>m)
{
if(n==)//如果没有数据那就直接按照格式输出零 ,一般不会有这种输入
{
cout<<<<endl<<<<endl;
continue;
}
for(int i=;i<=n;i++)//初始化,令每一个点成为独立的联通块
{
p[i]=i;
sum[i]=;//每个联通块中节点的个数为 1
} int a,b;
for(int i=;i<=m;i++)
{
cin>>a>>b;
int fa=find(a);//查找a的头节点
int fb=find(b);//查找b的头节点
if(fa!=fb)//如果头节点不同
{
p[fa]=fb;//将两个点合并
sum[fb]+=sum[fa];//并且使新头节点中的个数加上新连接的联通块所含节点的个数
}
}
int count=;
for(int i=;i<=n;i++)
{
if(p[i]==i)//计算联通块的数量
{
count++;
}
}
cout<<count<<endl;
int flag=;
for(int i=;i<=n;i++)
{
if(p[i]==i)
{
if(flag==)cout<<" ";
flag=;
cout<<sum[i];
}
}
cout<<endl;
}
return ;
}

这个题目利用DFS求解也可以。

要建立一个二维数据,将要连接点的点连在一起,并且用一个一位数据记录每个点是否被搜索过;

代码如下:

 #include<iostream>
#include<cstring>
using namespace std;
const int maxn=;
int map[maxn][maxn];
int vis[maxn];
int tot;
int n,m;
void dfs(int s)
{
tot++;
vis[s]=;
for(int i=;i<=n;i++)
if(!vis[i]&&map[s][i])//当从1到n都搜索一遍后 变会自动停止
{
dfs(i);
}
}
int main()
{
int now=;
int v,u;
while(cin>>n>>m)
{
tot=;
now=;
int sum[maxn];
memset(map,,sizeof(map));
memset(vis,,sizeof(vis));
for(int i=;i<=m;i++)
{
scanf("%d%d",&u,&v);
map[u][v]=map[v][u]=;
}
for(int i=;i<=n;i++)
{
if(vis[i]==)
{
tot=;
dfs(i);
sum[++now]=tot;
}
}
cout<<now<<endl;
for(int i=;i<=now;i++)
{
if(i>)cout<<" ";
cout<<sum[i];
}
cout<<endl;
}
return ;
} 利用BFS做也是比较方便的; 利用队栈保存每次搜索到的数据,并且在处理完成它的子节点后删除;同时利用一个数组记录是否拜访过它; #include <cstdio>
#include <cstring>
#include<iostream>
#include <queue>
using namespace std;
#define N 100
int n,m;
int map[N][N];
int mk[N];
int sum[N];
int total;
void bfs(int s)
{
queue <int> Q;
Q.push(s);
mk[s]=;
while(!Q.empty())
{
int u=Q.front();Q.pop();
total++;
for(int i=;i<=n;i++)
{
if(map[u][i]&&!mk[i])
{
mk[i]=;
Q.push(i);
}
}
}
}
int main()
{
int u,v;
int now=;
while(scanf("%d%d",&n,&m)==)
{
now=;
memset(map,,sizeof(map));
memset(mk,,sizeof(mk));
for(int i=;i<=m;i++)
{
scanf("%d%d",&u,&v);
map[u][v]=map[v][u]=;
}
for(int i=;i<=n;i++)
{if(mk[i]==)
{
total=;
bfs(i);
sum[++now]=total;
}
}
cout<<now<<endl;
for(int i=;i<=now;i++)
{
if(i>)cout<<" ";
cout<<sum[i];
}
cout<<endl;
}
return ;
}

以上三个方法,都是比较容易理解上手的,能够很好的提高做类似题目的能力;

分别利用并查集,DFS和BFS方法求联通块的数量的更多相关文章

  1. 【紫书】Oil Deposits UVA - 572 dfs求联通块

    题意:给你一个地图,求联通块的数量. 题解: for(所有还未标记的‘@’点) 边dfs边在vis数组标记id,直到不能继续dfs. 输出id及可: ac代码: #define _CRT_SECURE ...

  2. POJ1291-并查集/dfs

    并查集 题意:找出给定的这些话中是否有冲突.若没有则最多有多少句是对的. /* 思路:如果第x句说y是对的,则x,y必定是一起的,x+n,y+n是一起的:反之x,y+n//y,x+n是一起的. 利用并 ...

  3. hdu6200 mustedge mustedge mustedge (并查集+dfs序树状数组)

    题意 给定一个n个点m条边无向图(n,m<=1e5) 支持两个操作 1.添加一条边 2.询问点u到点v的所有路径中必经边的条数 操作数<=1e5 分析 第一眼看起来像是要动态维护无向图的边 ...

  4. 第46届ICPC澳门站 K - Link-Cut Tree // 贪心 + 并查集 + DFS

    原题链接:K-Link-Cut Tree_第46屆ICPC 東亞洲區域賽(澳門)(正式賽) (nowcoder.com) 题意: 要求一个边权值总和最小的环,并从小到大输出边权值(2的次幂):若不存在 ...

  5. 【并查集缩点+tarjan无向图求桥】Where are you @牛客练习赛32 D

    目录 [并查集缩点+tarjan无向图求桥]Where are you @牛客练习赛32 D PROBLEM SOLUTION CODE [并查集缩点+tarjan无向图求桥]Where are yo ...

  6. 利用DFS求联通块个数

    /*572 - Oil Deposits ---DFS求联通块个数:从每个@出发遍历它周围的@.每次访问一个格子就给它一个联通编号,在访问之前,先检查他是否 ---已有编号,从而避免了一个格子重复访问 ...

  7. HDU 1232 并查集/dfs

    原题: http://acm.hdu.edu.cn/showproblem.php?pid=1232 我的第一道并查集题目,刚刚学会,我是照着<啊哈算法>这本书学会的,感觉非常通俗易懂,另 ...

  8. 1021.Deepest Root (并查集+DFS树的深度)

    A graph which is connected and acyclic can be considered a tree. The height of the tree depends on t ...

  9. POJ 1562 Oil Deposits (并查集 OR DFS求联通块)

    Oil Deposits Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 14628   Accepted: 7972 Des ...

随机推荐

  1. 【转】cocos2d-x如何优化内存的应用

    原地址:http://cblog.chinadaily.com.cn/blog-942327-4327173.html 注:自身以前也写过cocos2d-x如何优化内存的应用,以及内存不够的情况下怎么 ...

  2. CSP201709-1:打酱油

    引言:CSP(http://www.cspro.org/lead/application/ccf/login.jsp)是由中国计算机学会(CCF)发起的"计算机职业资格认证"考试, ...

  3. [Clr via C#读书笔记]Cp5基元类型引用类型值类型

    Cp5基元类型引用类型值类型 基元类型 编译器直接支持的类型,基元类型直接映射到FCL中存在的类型. 作者希望使用FCL类型名称而避免使用关键字.他的理由是为了更加的清晰的知道自己写的类型是哪种.但是 ...

  4. [转]Excel数据转化为sql脚本

    在实际项目开发中,有时会遇到客户让我们把大量Excel数据导入数据库的情况.这时我们就可以通过将Excel数据转化为sql脚本来批量导入数据库. 1 在数据前插入一列单元格,用来拼写sql语句. 具体 ...

  5. matlab 常用集合相关的函数

    Matlab常用的集合相关的函数如下:     union(A,B)              %求集合A和集合B的并集     intersect(A,B)             %求集合A和集合 ...

  6. str和repr

    在Python2.6和Python3.0以及更早的版本中,在交互式模式下的输出本质上是使用repr,因此对于一些浮点数运算,会显示很多位: 4 / 5.0 #0.8000000000000004 但是 ...

  7. 《剑指Offer》题十一~题二十

    十一.旋转数组的最小数字 题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如,数组{3, 4, 5, 1, 2}为{ ...

  8. 自测之Lesson6:文件I/O

    题目:区分文件I/O和标准I/O. 区别: ①首先两者一个显著的不同点在于,标准I/O默认采用了缓冲机制,比如调用fopen函数,不仅打开一个文件,而且建立了一个缓冲区(读写模式下将建立两个缓冲区), ...

  9. 常用web资源

    ip相关 新浪:http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js&ip=220.181.38.110 (不带参数本机) ...

  10. LintCode-56.两数之和

    两数之和 给一个整数数组,找到两个数使得他们的和等于一个给定的数 target. 你需要实现的函数twoSum需要返回这两个数的下标, 并且第一个下标小于第二个下标.注意这里下标的范围是 1 到 n, ...