题目描述
小明终于忙玩了各种各样的课程,终于可以继续学习算法了。
他在图论书上看到了树,树有许许多多特殊的性质。小明一下子就喜欢上了这种特殊的树。
于是,他发明了自己的对于无向图的评分方法。
一个无向图的分数定义为,各个连通块是树的数量。
现在给定一个n个点m条边的无向图,问在小明的评分方法下,分数为多少。
一个连通块是树,当且仅当边数比点数少1。
输入
第一行两个整数n和m,表示图的点数和边数。
第二行有m对整数,u和v表示,结点u和节点v之间有边。给出的无向图不存在重边。
输出
输出一行包括一个整数,表示无向图的评分,也就是树的数量。
样例输入
8 6
1 2
1 3
2 4
5 6
6 7
5 7
样例输出
2
提示
数据范围
20%的数据,1<=n<=2000
100%的数据,1<=n<=100000,0<=m<=min(n*(n-1)/2,200000)
Code:
#include <iostream>
#include <vector>
#define SIZE 100001
using namespace std;
vector<int> v[SIZE];
bool visited[SIZE], flag;
void dfs(int k, int last) // dfs遍历连通子图
{
int i;
visited[k] = true;
for (i = 0; i < v[k].size(); i++)
{
if (visited[v[k][i]]) // 如果这个店的连通点被访问过
{
if (v[k][i] != last) // 并且不是上一个过来的点
{
flag = true; // 我们就认为连通图中存在环,不是树
} // 但是还要继续遍历连通图,所以不返回
}
else // 如果这个点没有被访问过
{
dfs(v[k][i], k); // 就去访问这个点
}
}
}
int main(void)
{
int n, m, x, y, i, res = 0;
scanf("%d%d", &n, &m);
while (m--)
{
scanf("%d%d", &x, &y); // 输入
v[x].push_back(y);
v[y].push_back(x);
}
for (i = 1; i <= n; i++)
{
if (!visited[i]) // 如果这个点没有被访问过
{
flag = false;
dfs(i, -1); // 就开始遍历连通子图
if (!flag) // 如果dfs()确定了这个连通子图是一棵树
{
++res; // 那么就把树的总数+1
}
}
}
printf("%d", res); // 最后输出结果
return 0;
}