自学内容网 自学内容网

洛谷 P2863

[USACO06JAN] The Cow Prom S

题目描述

有一个 n n n 个点, m m m 条边的有向图,请求出这个图点数大于 1 1 1 的强连通分量个数。

输入格式

第一行为两个整数 n n n m m m

第二行至 m + 1 m+1 m+1 行,每一行有两个整数 a a a b b b,表示有一条从 a a a b b b 的有向边。

输出格式

仅一行,表示点数大于 1 1 1 的强连通分量个数。

样例 #1

样例输入 #1

5 4
2 4
3 5
1 2
4 1

样例输出 #1

1

提示

数据规模与约定

对于全部的测试点,保证 2 ≤ n ≤ 1 0 4 2\le n \le 10^4 2n104 2 ≤ m ≤ 5 × 1 0 4 2\le m\le 5\times 10^4 2m5×104 1 ≤ a , b ≤ n 1 \leq a, b \leq n 1a,bn

#include <bits/stdc++.h>
using namespace std;
#define N 10005
vector<int> G[N];
//vis 只记录当前连通分量的访问情况(即是否可达),used记录全局的 
bool used[N] = {0}, vis[N] ={0};

int indexx = 0,dfn[N] = {0},low[N] = {0},color[N] = {0};
int colornum = 0;
stack<int> s;
void paint()
{
int now = s.top();
s.pop();
color[colornum]++;
//这里释放点的访问情况(是否在栈中/是否是当前的联通中) 
//记录一个点是否在栈中是为了正确判断节点之间的可达性,进而确定哪些节点构成了强连通分量。 
vis[now] = false; 
}
void dfs(int now)
{
if(vis[now] == true) return ;
vis[now] = true;
used[now] = true;
s.push(now);
low[now] = dfn[now] = ++indexx;
for(int i=0;i<G[now].size();i++)
{
int child = G[now][i];
//如果已经记录时间戳但没有访问的节点不会进入栈中 
if(dfn[child] == 0)
{
dfs(child);
low[now] = min(low[now],low[child]);
}//没有分配时间戳则说明未被先前的联通量所搜索
//分配了时间戳也要检测是否可达(在栈中) 
else if(vis[child])//else分支一定要加,否则一定会进入 
{
low[now] = min(low[now],dfn[child]);
}
}
if(low[now] == dfn[now])
{
colornum++;
while(s.top()!=now)
{
paint();
}
paint();
}
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=0;i<m;i++)
{
int from,to;
cin>>from>>to;
G[from].push_back(to);
}
for(int i = 1;i<=n;i++)
{
if(used[i] == false) dfs(i);
}
int ans = 0;
for(int i = 1;i<=colornum;i++)
{
if(color[i]>1) ans++;
}
cout<<ans;
return 0;
 } 

原文地址:https://blog.csdn.net/m0_65414734/article/details/137672062

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!