1798 Problem A 第一题

问题 A: 第一题

时间限制: 1 Sec  内存限制: 32 MB
提交: 169  解决: 25
 

题目描述

该题的目的是要你统计图的连通分支数。

输入

每个输入文件包含若干行,每行两个整数i,j,表示节点i和j之间存在一条边。

输出

输出每个图的联通分支数。

样例输入

1 4
4 3
5 5

样例输出

2

经验总结

这一题可以说是很坑了
    首先题目没有说明结点编号的范围,事实上测试数据结点编号在1~1e6之间,标记数组稍微小一个数量级都会出现段错误
    然后,就是要注意会出现自己指向自己的边,在使用邻接表进行记录时要区分一下,不然会有重复元素,但实际上不区分,也是可以通过的,就是耗时多一些
    最后,就是如何访问顶点的问题了,我起初使用set集合记录所有顶点,但是由于数组很大,所以内存多了一点点,就超了,刚才又试了一下,5e5的数量级可以通过测试!!就是1e6数组大小小一半,这样用其他的结构(比如map用做标记,set用做结点)就不会超内存了,不过这里,还是建议直接在输入数据的时候就保存一个最大编号的变量,这样直接for循环就可以,省事而且高效。
    这次也是学到了一些教训,比如,数组超内存限制使用其他结构,如果不在乎提交次数并且知道程序不通过的原因就是超出内存,就可以一半一半的减小,取试探测试数组的最大值,这样说不定可以留出一些空间使用其他的小型工具。

正确代码

#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
const int maxn=500010;
vector<int> Adj[maxn];
bool flag[maxn]={false};

void DFS(int n)
{
	flag[n]=true;
	for(int i=0;i<Adj[n].size();++i)
	{
		int v=Adj[n][i];
		if(flag[v]==false)
		{
			DFS(v);
		}
	}
}
int main()
{
	int n,m,max=-1;
	while(~scanf("%d",&n))
	{
		scanf("%d",&m);
		if(m!=n)
		{
			Adj[n].push_back(m);
			Adj[m].push_back(n);
		}
		else
		{
			Adj[n].push_back(m);
		}
		max=max>n?max:n;
		max=max>m?max:m;
	}
	memset(flag,0,sizeof(flag));
	int number=0;
	for(int i=1;i<=max;++i)
	{
		if(flag[i]==false&&Adj[i].size()!=0)
		{
			number++;
			DFS(i);
		}
	}
	printf("%d\n",number);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/a845717607/article/details/81708837
今日推荐