图论-连通块-DFS-BFS
题目大意
给出一个有若干个连通块无向图,求有多少个连通块满足 该连通块构成一个环
一个环,就是一个形如下图的连通块,满足点数与边数相等,且不应有多余的边
第一个想到的就是 dfs 判环:如果要访问的节点
y
y
y 被访问过了,并且
y
y
y 为当前连通块遍历的第一个节点
t
o
p
top
top (也就是连通块遍历完了),return true
;如果
y
≠
t
o
p
y \ne top
y=top return 0
dfs 代码
bool dfs(int x,int fa,int top)
{
vis[x]=1;
for(int i=0;i<e[x].size();++i)
{
int y=e[x][i];
if(y==fa)continue;
if(vis[y] && y!=top)return 0;
if(y==top)return 1;
bool flag=dfs(y,x,top);
if(flag)return 1;
}
return 0;
}
写完发现过不了样例,又加了个 bfs 计算点数和边数,并判等
bool bfs(int s)
{
queue <int> q;
int cnt=0,tot=0;
vist[s]=1,q.push(s);
while(q.size())
{
int x=q.front();
q.pop();
++cnt;
if(d[x]!=2)return 0; // 判断度数,后面会讲
for(int i=0;i<e[x].size();++i)
{
int y=e[x][i];
++tot;
if(vist[y])continue;
vist[y]=1,q.push(y);
}
}
tot>>=1;
return cnt==tot;
}
提交上去又双叒叕在第三个点挂了,仔细想了想后,发现环中的每个节点度数都为 2 2 2 ,加了判断度数后才AC
完整代码:
#include<cstdio>
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
const int Maxn=200000+20,inf=0x3f3f3f3f;
int n,m,ans;
bool vis[Maxn],vist[Maxn];
int d[Maxn];
vector <int> e[Maxn];
inline int read()
{
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0' && ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
return s*w;
}
bool dfs(int x,int fa,int top)
{
vis[x]=1;
for(int i=0;i<e[x].size();++i)
{
int y=e[x][i];
if(y==fa)continue;
if(vis[y] && y!=top)return 0;
if(y==top)return 1;
bool flag=dfs(y,x,top);
if(flag)return 1;
}
return 0;
}
bool bfs(int s)
{
queue <int> q;
int cnt=0,tot=0;
vist[s]=1,q.push(s);
while(q.size())
{
int x=q.front();
q.pop();
++cnt;
if(d[x]!=2)return 0;
for(int i=0;i<e[x].size();++i)
{
int y=e[x][i];
++tot;
if(vist[y])continue;
vist[y]=1,q.push(y);
}
}
tot>>=1;
return cnt==tot;
}
int main()
{
// freopen("in.txt","r",stdin);
n=read(),m=read();
for(int i=1;i<=m;++i)
{
int x=read(),y=read();
e[x].push_back(y);
e[y].push_back(x);
d[x]++,d[y]++;
}
for(int i=1;i<=n;++i)
{
if(vis[i])continue;
bool flag=dfs(i,0,i) && bfs(i);
if(flag)++ans;
//printf("i = %d %d\n",i,flag);
}
printf("%d\n",ans);
return 0;
}