POJ 1236 Network of Schools (有向图的强连通分量)

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

【题意】给出几个点和有向边,问1:取其中几个点能到达所有的点;2:最少加几条边使其成为强连通图。

【思路】用tarjan算法将强连通分支缩点;设缩点之后入度为0的个数为m,出度为0的个数为n,1的答案为m,2的答案为max(m,n)

【题解参考】https://www.cnblogs.com/kuangbin/p/3182611.html

【tarjan算法】https://blog.csdn.net/qq_34374664/article/details/77488976

【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int M=505;
int n;
int mp[M][M];
bool inthestack[M];
int LOW[M];
int DFN[M],cnt;
int Stack[M],si;
int scc,Belong[M];

void Tarjan(int x)
{
    LOW[x]=DFN[x]=++cnt;
    Stack[si++]=x;
    inthestack[x]=1;
    for(int i=1; i<=n; i++)
    {
        if(mp[x][i]>0)
        {
            if(DFN[i]==0)
            {
                Tarjan(i);
                LOW[x]=min(LOW[x],LOW[i]);
            }
            else if(DFN[i]!=0&&inthestack[i])
            {
                LOW[x]=min(LOW[x],DFN[i]);
            }
        }
    }int v;
    if(LOW[x]==DFN[x])
    {scc++;
        do
        {
             v= Stack[--si];
            Belong[v] = scc;
            inthestack[v] = 0;
        }
        while( v!= x);
    }
}

void init()
{
    memset(mp,0,sizeof(mp));
    memset(inthestack,0,sizeof(inthestack));
    memset(DFN,0,sizeof(DFN));
    memset(LOW,0,sizeof(LOW));
    cnt=si=0;
}
int main()
{
    scanf("%d",&n);
    init();
    for(int i=1; i<=n; i++)
    {
        int t;
        while(~scanf("%d",&t)&&t)
        {
            mp[i][t]=1;
        }
    }
    scc=0;
    for(int i=1;i<=n;i++)
         if(!DFN[i])Tarjan(i);
//    for(int i=1;i<=n;i++)printf("%d ",LOW[i]);
//    printf("\n");
//
    if(scc == 1)
    {
        printf("1\n0\n");
        return 0;
    }
    int in[M],out[M];
    for(int i = 1;i <= scc;i++)
       in[i] = out[i] = 0;
    for(int u = 1;u <= n;u++)
    {
        for(int v = 1;v <= n;v++)
        {
            if(u==v)continue;
            if(mp[u][v]==0)continue;
            if(Belong[u] != Belong[v])
            {
                in[Belong[v]]++;
                out[Belong[u]]++;
            }
        }
    }
    int ans1=0,ans2=0;
    for(int i = 1;i <= scc;i++)
    {
        if(in[i]==0)ans1++;
        if(out[i]==0)ans2++;
    }
    printf("%d\n%d\n",ans1,max(ans1,ans2));

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值