hdu 4635 Strongly connected (强连通缩点)

来源:互联网 发布:win7启用网络发现 编辑:程序博客网 时间:2024/06/05 08:58
/*题意:给你一个有向图,问你最多能添加多少条边使得这个图依然不是强联通的。做法:1,求出图中的所有强连通分量2,把上述的强连通分量缩成一个点。3,问题现在变成问一个完全图,最少需要去除多少条边使得这个图不强联通,那么肯定是去除所有强联通分量中含有点数最少的点的所有进边。*/# include <stdio.h># include <algorithm># include <string.h># include <vector>#include <iostream>using namespace std;# define MAXN 20010# define MAXM 50010struct Edge{    int v,next;} edge[MAXM];int first[MAXN],Stack[MAXN],DFN[MAXN],Low[MAXN],color[MAXM];int instack[MAXN];int in[MAXN],out[MAXN];int sum[MAXN];int n,m,cnt,scnt,top,tot;void init(){    cnt=0;    scnt=top=tot=0;    memset(first,-1,sizeof(first));    memset(DFN,0,sizeof(DFN));    memset(sum,0,sizeof(sum));}void add(int u,int v){    edge[tot].v=v;    edge[tot].next=first[u];    first[u]=tot++;}void Tarjan(int v){    int t;    DFN[v]=Low[v]=++tot;    instack[v]=1;    Stack[top++]=v;    for(int e=first[v]; e!=-1; e=edge[e].next)    {        int j=edge[e].v;        if(!DFN[j])        {            Tarjan(j);            Low[v]=min(Low[v],Low[j]);        }        else if(instack[j])            Low[v]=min(Low[v],DFN[j]);    }    if(DFN[v]==Low[v])    {        scnt++;//连通分量+1        do        {            sum[scnt]++;//每个连通分量中的个数            t=Stack[--top];            instack[t]=0;            color[t]=scnt;///Belong[]为每个结点所对应的强连通分量标号数组        }        while(t!=v);    }}void slove(){    for(int i=1; i<=n; i++)        if(!DFN[i])            Tarjan(i);}int main(){    int t,cas=0;    scanf("%d",&t);    while(t--)    {        scanf("%d%d",&n,&m);        init();        for(int i=0; i<m; i++)        {            int u,v;            scanf("%d%d",&u,&v);            add(u,v);        }        slove();        printf("Case %d: ",++cas);        if(scnt==1)///强连通        {            printf("-1\n");        }        else        {            memset(in,0,sizeof(in));            memset(out,0,sizeof(out));            for(int i=1; i<=n; i++)            {                for(int e=first[i]; e!=-1; e=edge[e].next)                {                    if(color[i]!=color[edge[e].v])                    {                        in[color[edge[e].v]]++;                        out[color[i]]++;                    }                }            }            int ans1=0,ans2=0;            int maxx=0;            for(int i=1; i<=scnt; i++)            {                if(in[i]==0||out[i]==0)                {                    int x=sum[i];///一个分量中连通的个数                    int y=n-sum[i];                    int tmp=x*(x-1)+y*(y-1)+x*y-m;//可以连接的最多边                    maxx=max(maxx,tmp);                }            }            printf("%d\n",maxx);        }        //  printf("%d %d\n",ans1,ans2);    }    return 0;}

0 0