• 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;//入度要加边,出度也要加边
        }
    }
    

      //一些细节需要注意

    不怕万人阻挡,只怕自己投降。
  • 相关阅读:
    OC-字典
    作业
    block语法排序 遍历
    oc-NSArray
    oc之获取系统当前时间的方法
    修改mysql的默认字符集
    mysql查询结果添加序列号
    PHP Socket 编程过程详解
    一篇详细的 Mysql Explain 详解
    阿里云云主机挂载数据盘,格式化硬盘(新购云主机)(转)
  • 原文地址:https://www.cnblogs.com/newstartCY/p/11574083.html
Copyright © 2020-2023  润新知