POJ1236

//Tarjan算法   缩点变形
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
const int maxn = 100 + 15;
vector<int> Grape[maxn];
bool vis[maxn];
int dfn[maxn],low[maxn],arr[maxn],chudu[maxn],rudu[maxn];
int total,cnt;
stack<int> s;
void tarjan(int u)
{
    dfn[u] = low[u] = ++total;
    s.push(u);
    vis[u] = true;//u节点入栈
    for(int i=0;i!=Grape[u].size();++i)
    {
        int v = Grape[u][i];
        if(!dfn[v])
        {
            tarjan(v);
            low[u] = min(low[u],low[v]);
        }else if(vis[v])
            low[u] = min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u])//找到连通分图根节点
    {
        ++cnt;//标记连通分量的个数
        int v;
        do{
            v = s.top();
            s.pop();
            vis[v] = false;//出栈
            arr[v] = cnt;
        }while(v!=u);
    }
}
int main()
{
    int n;
    while(cin>>n)
    {
        for(int i=1;i<=n;++i)
            Grape[i].clear();
        int v;
        for(int i=1;i<=n;++i)
        {
            while(cin>>v&&v)
                Grape[i].push_back(v);
        }
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(arr,0,sizeof(arr));
        memset(chudu,0,sizeof(chudu));
        memset(rudu,0,sizeof(rudu));
        total = 0,cnt = 0;
        for(int v=1;v<=n;++v)
            if(!dfn[v])
                tarjan(v);
        //统计出入度
        int anschu = 0,ansru = 0;
        for(int u=1;u<=n;++u)
        {
            for(int i=0;i!=Grape[u].size();++i)
            {
                int v = Grape[u][i];
                if(arr[u]!=arr[v])
                {
                    ++chudu[arr[u]];
                    ++rudu[arr[v]];
                }
            }
        }
        for(int v=1;v<=cnt;++v)
        {
            if(!chudu[v])
                ++anschu;
            if(!rudu[v])
                ++ansru;
        }
        if(cnt==1)
        {
            cout<<1<<endl;
            cout<<0<<endl;
            continue;
        }//只存在一个强连通分量时,不需加边
        cout<<ansru<<endl;
        cout<<max(anschu,ansru)<<endl;//入度要加边,出度也要加边
    }
}

  //一些细节需要注意

posted on 2019-09-23 18:57  chengyulala  阅读(86)  评论(0编辑  收藏  举报

导航