hdu 2767 Proving Equivalences //tarjan+缩点

题目链接

题意:给n个点和m条有向边,问最少再加几条边使其变成强连通图。

先tarjan跑一遍,如果是强连通图就输出0。否则输出max(入度为0的点个数,出度为0的点个数)。

#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define N 22000
#define M 55000

using namespace std;

struct node
{
    int to,next;
}e[M];

int dfn[N],low[N],head[N],in[N],out[N],cnt,scnt,top,q[N],v[N],belong[N],n,m;

void init()
{
    memset(head,-1,sizeof(head));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    memset(belong,0,sizeof(belong));
    cnt=scnt=top=0;
}

void add_edge(int u,int v)
{
    e[cnt].to=v;
    e[cnt].next=head[u];
    head[u]=cnt++;
}

void tarjan(int u)
{
    int t;
    low[u]=dfn[u]=cnt++;
    q[top++]=u;
    v[u]=1;
    for(int i=head[u];i+1;i=e[i].next)
    {
        int c=e[i].to;
        if(!dfn[c])
        {
            tarjan(c);
            low[u]=min(low[u],low[c]);
        }
        else if(v[c])
            low[u]=min(low[u],dfn[c]);
    }
    if(low[u]==dfn[u])
    {
        scnt++;
        do
        {
            t=q[--top];
            v[t]=0;
            belong[t]=scnt;
        }while(t!=u);
    }
}

void solve()
{
    for(int i=1;i<=n;i++)
        if(!dfn[i]) tarjan(i);
    if(scnt==1)
    {
        cout<<0<<endl;
        return ;
    }
    for(int i=1;i<=n;i++)
        for(int j=head[i];j+1;j=e[j].next)
        {
            int t=e[j].to;
            if(belong[i]!=belong[t])
            {
                in[belong[t]]++;
                out[belong[i]]++;
            }
        }
    int a=0,b=0;
    for(int i=1;i<=scnt;i++)
    {
        if(in[i]==0)    a++;
        if(out[i]==0)   b++;
    }
    cout<<max(a,b)<<endl;
}

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        cin>>n>>m;
        init();
        for(int i=0;i<m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v);
        }
        solve();
    }
}

你可能感兴趣的:(模板,ACM,HDU,Tarjan,缩点)