POJ1236学校网络——tarjan

题目:http://poj.org/problem?id=1236

Tarjan+缩点。温习一下Tarjan的写法。

1.在缩点后的TAG中,有几个联通块等价于有几个入度为0的点!

2.把它们都联通相当于给每个入度为0的点都连一条入边,给每个出度为0的点都连一条出边,所以二者取max即可。

* 有向图是强联通分量的充要条件是没有入度为0的点也没有出度为0的点。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=105;
int n,head[N],rd[N],cd[N],dfn[N],low[N],xnt,cnt,tim;
int stack[N],top,r,c,col[N],ans,rrd[N];
bool in[N];
struct Edge{
    int next,from,to;
    Edge(int n=0,int f=0,int t=0):next(n),from(f),to(t) {}
}edge[N*N];
void tarjan(int cur)
{
    dfn[cur]=low[cur]=++tim;
    stack[++top]=cur;in[cur]=1;
    for(int i=head[cur],v;i;i=edge[i].next)
    {
        if(in[v=edge[i].to])
            low[cur]=min(low[cur],dfn[v]);
        else if(!dfn[v])tarjan(v),low[cur]=min(low[cur],low[v]);
    }
    if(dfn[cur]==low[cur])
    {
        cnt++;
        while(cur!=stack[top])in[stack[top]]=0,col[stack[top--]]=cnt;
        in[stack[top]]=0;col[stack[top--]]=cnt;
    }
}
int main()
{
    scanf("%d",&n);int x;
    for(int i=1;i<=n;i++)
        while(1)
        {
            scanf("%d",&x);if(!x)break;
            edge[++xnt]=Edge(head[i],i,x);head[i]=xnt;
        }
    for(int i=1;i<=n;i++)
        if(!dfn[i])tarjan(i);//!dfn[i]
    for(int i=1,v,u;i<=xnt;i++)
        if(col[u=edge[i].from]!=col[v=edge[i].to])rd[col[v]]++,cd[col[u]]++;
    for(int i=1;i<=cnt;i++)
    {
        if(!rd[i])r++;if(!cd[i])c++;
    }    
    if(cnt==1)// 
    {
        printf("1\n0");return 0;
    }
    printf("%d\n%d",r,max(r,c));
    return 0;
}

 

posted on 2018-04-17 18:37  Narh  阅读(116)  评论(0编辑  收藏  举报

导航