P2863 [USACO06JAN] The Cow Prom S

P2863 [USACO06JAN] The Cow Prom S

题目描述

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

输入格式

第一行为两个整数 \(n\)\(m\)

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

输出格式

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

输入输出样例 #1

输入 #1

5 4
2 4
3 5
1 2
4 1

输出 #1

1

说明/提示

数据规模与约定

对于全部的测试点,保证 \(2\le n \le 10^4\)\(2\le m\le 5\times 10^4\)\(1 \leq a, b \leq n\)
首先我犯了两个错误,第一就是在点弹出栈的时候没有将它的vis数组标记为0;
第二就是,寻找连通量时直接从第一个节点遍历,但第一个点是孤立的,无法拓展到其他点,所以应当遍历每一个点,如果它没有在其他点遍历的时候被遍历到,就让他进dfs函数

#include<iostream>
#include<vector>
#include<stack>
#define int long long 
using namespace std;
const int N=1e5+5;
vector<int>v[N];
int vis[N];
int dfsn[N];
int low[N];
int t=0;
stack<int>s;
int ans=0;
void dfs(int x){
    dfsn[x]=low[x]=++t;
    s.push(x);
    vis[x]=1;
    for(int i=0;i<v[x].size();i++){
        int y=v[x][i];
        if(!dfsn[y]){
            dfs(y);
            low[x]=min(low[x],low[y]);
        }
        else if(vis[y])low[x]=min(low[x],dfsn[y]);
    }
    if(low[x]==dfsn[x]){
        int cnt=0;
        while(s.top()!=x){
            vis[s.top()]=0;
            s.pop();
            cnt++;
        }
        vis[s.top()]=0;
        s.pop();
        cnt++;
        if(cnt>1)ans++;
    }
}
signed main(){
    int n,m;
    cin>>n>>m;
    while(m--){
        int a,b;
        cin>>a>>b;
        v[a].push_back(b);
    }
    for(int i=1;i<=n;i++)if(!dfsn[i])dfs(i);
    cout<<ans;
    return 0;
}
posted @ 2025-03-12 21:53  郭轩均  阅读(80)  评论(0)    收藏  举报