【模板】刻录光盘——Kosaraju求SCC,缩点

题目:http://www.sqyoj.club/problem.php?id=1018

分析:求出SCC后缩点,重新构图,统计新图中入度为0的点的个数即为答案。下面代码是用Kosaraju求SCC。

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int num,head[201],fnum,fhead[201];
int n,x;
int vis[201],fvis[201];
int in[201],out[201];
int nd[201],cns,scc;
int belong[201];
int ans;
struct Edge{
    int from,to,next;
};
Edge edge[80000],fedge[80000];
void join(int from,int to){
    ++num;
    edge[num].from=from;
    edge[num].to=to;
    edge[num].next=head[from];
    head[from]=num;
}
void fjoin(int from,int to){
    ++fnum;
    fedge[fnum].from=from;
    fedge[fnum].to=to;
    fedge[fnum].next=fhead[from];
    fhead[from]=fnum;
}
void dfs(int v){
    for(int i=head[v];i!=-1;i=edge[i].next){
        int to=edge[i].to;
        if(!vis[to]){
            vis[to]=1;
            dfs(to);
            nd[++cns]=to;
        }
    }
}
void fdfs(int v){
    for(int i=fhead[v];i!=-1;i=fedge[i].next){
        int to=fedge[i].to;
        if(!fvis[to]){
            fvis[to]=1;
            belong[to]=scc;
            fdfs(to);
        }
    }
}
void buildgraph(){
    for(int i=1;i<=n;i++){
        for(int j=head[i];j!=-1;j=edge[j].next){
            int to=edge[j].to;
            if(belong[i]==belong[to])continue;
            out[ belong[i] ]++;
            in[ belong[to] ]++;
        }
    }
}
int main(){
    memset(head,-1,sizeof(head));
    memset(fhead,-1,sizeof(head));
    cin>>n;
    for(int i=1;i<=n;i++)
        while(scanf("%d",&x) && x){
            join(i,x);
            fjoin(x,i);
        }
     
    /*Kosaraju*/
    for(int i=1;i<=n;i++)
        if(!vis[i]){
            vis[i]=1;
            dfs(i);
            nd[++cns]=i;
        }
    for(int i=cns;i>=1;i--)
        if(!fvis[ nd[i] ]){
            fvis[ nd[i] ]=1;
            scc++;
            belong[ nd[i] ]=scc;
            fdfs( nd[i] );
        }
     
    /*缩点构图*/   
    buildgraph();
    for(int i=1;i<=scc;i++)if(in[i]==0)ans++;
    cout<<ans;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值