hdu 4635 强连通度缩点

思路:想用Tarjan算法进行缩点,并记录每个连通分支的点数。缩点完毕过后,找出所有出度或入度为0的连通分量,假设该连通分量的点数为num[i],那么

ans=Max(ans,(n-num-1)*(n-num)+(num-1)*num+(n-num)*num-m);

#include<iostream>

#include<cstring>

#include<cstdio>

#include<algorithm>

#define Maxn 100010

#define Max(a,b) (a)>(b)?(a):(b)

using namespace std;

int head[Maxn],vi[Maxn],dfn[Maxn],low[Maxn],e,lab,top,Stack[Maxn],flag,id[Maxn],in[Maxn],out[Maxn],n,m,Ei[Maxn],num;

__int64 ans;

struct Edge{

    int u,v,next;

}edge[Maxn];

void init()

{

    memset(head,-1,sizeof(head));

    memset(vi,0,sizeof(vi));

    memset(dfn,0,sizeof(dfn));

    memset(low,0,sizeof(low));

    memset(in,0,sizeof(in));

    memset(out,0,sizeof(out));

    memset(Ei,0,sizeof(Ei));

    e=lab=top=flag=num=0;

    ans=0;

}

void add(int u,int v)

{

    edge[e].u=u,edge[e].v=v,edge[e].next=head[u],head[u]=e++;

}

void Tarjan(int u)

{

    dfn[u]=low[u]=++lab;

    vi[u]=1;

    Stack[top++]=u;

    int i,j,v;

    for(i=head[u];i!=-1;i=edge[i].next)

    {

        v=edge[i].v;

        if(!dfn[v])

        {

            Tarjan(v);

            low[u]=min(low[u],low[v]);

        }

        if(vi[v])

            low[u]=min(low[u],dfn[v]);

    }

    if(low[u]==dfn[u])

    {

        ++num;

        int cnt=0;

        do{

            i=Stack[--top];

            vi[i]=0;

            id[i]=num;

            cnt++;

        }while(i!=u);

        Ei[num]=cnt;

        if(n==cnt)

        {

            flag=1;

            return ;

        }

    }

}

int solve()

{

    int i,j;

    for(i=1;i<=n;i++)

    {

        if(!dfn[i])

            Tarjan(i);

        if(flag)

            return 0;

    }

    return 1;

}

int main()

{

    int i,j,a,b,t,Case=0;

    scanf("%d",&t);

    while(t--)

    {

        init();

        scanf("%d%d",&n,&m);

        for(i=1;i<=m;i++)

        {

            scanf("%d%d",&a,&b);

            add(a,b);

        }

        if(!solve()||flag)

        {

            printf("Case %d: -1\n",++Case);

            continue;

        }

        for(i=1;i<=n;i++)

            for(j=head[i];j!=-1;j=edge[j].next)

            {

                int u=edge[j].u;

                int v=edge[j].v;

                if(id[u]!=id[v])

                {

                    in[id[v]]++;

                    out[id[u]]++;

                }

            }

        __int64 temp;

        for(i=1;i<=num;i++)

            if(in[i]==0||out[i]==0)

            {

                temp=(__int64)((n-Ei[i])*(n-Ei[i]-1)+Ei[i]*(Ei[i]-1)+(n-Ei[i])*Ei[i]-m);

                ans=Max(ans,temp);

            }

            printf("Case %d: %I64d\n",++Case,ans);

    }

    return 0;

}

 

你可能感兴趣的:(HDU)