图论--Tarjan求强联通分量

以下为普及+/提高- 难度
这篇我对Tarjan这个算法不作解释,不知道的戳这里.
tarjan这个算法在OI的图论题中很常用它在O(n+m) 的时间内可以求出所有强联通分量,然后可以将每一个强联通分量(通常是一个环)缩成一个点。
然后就是一道模板题:

洛谷 P2863 [USACO06JAN]牛的舞会The Cow Prom

这题已经水到我无话可说了,真的是模板,但是就是一点要注意的,强联通分量必须点数>1才可以算。
code:

#include<bits/stdc++.h>
using namespace std;
struct edge{
    int to,next;
}e[50001];
int n,m,tot,dfn_clock,num;
int head[10001];
int dfn[10001];
int low[10001];
int vis[10001];
int in[10001];
int s[10001],top;
void tarjan(int i){
    vis[i]=1;
    low[i]=dfn[i]=++dfn_clock;
    s[++top]=i;
    in[i]=1;
    for(int j=head[i];j;j=e[j].next){
        int u=e[j].to;
        if(!vis[u]){
            tarjan(u);
            low[i]=min(low[i],low[u]);
        }
        else if(in[u]){
            low[i]=min(low[i],dfn[u]);
        }
    }
    if(dfn[i]==low[i]){
        int cnt=0;
        while(i!=s[top]){
            in[s[top--]]=0;
            cnt++;
        }
        cnt++;
        in[s[top--]]=0;
        if(cnt>=2)num++;
    }
}
void addedge(int x,int y){
    tot++;
    e[tot].to=y;
    e[tot].next=head[x];
    head[x]=tot;
}
int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=m;i++){
        int x,y;
        scanf("%d %d",&x,&y);
        addedge(x,y);
    }
    for(int i=1;i<=n;i++){
        if(!vis[i]){
            tarjan(i);
        }
    }
    printf("%d",num);
    return 0;
}

以后我还会对这篇作些补充。。
to be continued

posted @ 2017-08-10 20:58  玫葵之蝶  阅读(167)  评论(0编辑  收藏  举报