POJ 1236 Network of Schools

之前对Kosaraju_Algorithm理解有误,现在彻底明白了。

Kosaraju_Algorithm:

•  step1:对原图G进行深度优先遍历,记录每个节点的离开时间。形成了一个森林(很多树)
•  step2:选择具有最晚离开时间的顶点,对反图GT进行遍历,删除能够遍历到的顶点,这些顶点构成一个强连通分量。
•  step3:如果还有顶点没有删除,继续step2,否则算法结束。
 
对于这个题目,第一问的答案就是缩点之后入度为0的节点的个数,第二问就是max(入度为0的结点个数,出入为0的结点个数)
如果本来就只有一个强连通分量,那么输出1 0就可以了。
 
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;

const int maxn=105;
int Dfn[maxn],U[100000],V[100000],Belong[maxn];
int In[maxn],Out[maxn],flag[maxn];
struct Point
{
    int id,dfn;
} point[maxn];
vector<int>G[maxn];
vector<int>FG[maxn];
int N,Tot;
int Sum,Block,in,out;

void init()
{
    for(int i=0; i<maxn; i++) G[i].clear();
    for(int i=0; i<maxn; i++) FG[i].clear();
    memset(Dfn,0,sizeof Dfn);
    memset(In,0,sizeof In);
    memset(Out,0,sizeof Out);
    memset(flag,0,sizeof flag);
    Tot=0;//时间戳
    Sum=0;//边的数目
    Block=0;//强连通分量的数目
    in=0;//统计入度为0的点的数目
    out=0;//统计出度为0的点的数目
}

bool cmp(const Point&a,const Point&b)
{
    return a.dfn>b.dfn;
}

void Dfs(int now)
{
    flag[now]=1;
    for(int i=0; i<G[now].size(); i++)
        if(!flag[G[now][i]])
            Dfs(G[now][i]);
    Tot++;
    Dfn[now]=Tot;
}

void dfs(int now)
{
    Belong[now]=Block;
    for(int i=0; i<FG[now].size(); i++)
        if(!Belong[FG[now][i]])
            dfs(FG[now][i]);
}

int main()
{
    while(~scanf("%d",&N))
    {
        init();
        for(int i=1; i<=N; i++)
        {
            while(1)
            {
                int v;
                scanf("%d",&v);
                if(!v) break;
                Sum++;
                U[Sum]=i;
                V[Sum]=v;
                G[i].push_back(v);
                FG[v].push_back(i);
            }
        }
        for (int i = 1; i <= N; i++) if (!flag[i]) Dfs(i);
        for(int i=0; i<N; i++)
            point[i].id=i+1, point[i].dfn=Dfn[i+1];
        sort(point,point+N,cmp);
        for(int i=0; i<N; i++)
            if(!Belong[point[i].id])
                Block++,dfs(point[i].id);
        for(int i=1; i<=Sum; i++)
            if(Belong[U[i]]!=Belong[V[i]])
                Out[Belong[U[i]]]++,In[Belong[V[i]]]++;
        for(int i=1; i<=Block; i++)
        {
            if(!In[i]) in++;
            if(!Out[i]) out++;
        }
        if(Block==1) printf("1
0
");
        else printf("%d
%d
",in,max(in,out));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zufezzt/p/4766222.html