hdu-4635(有向图缩点+判断强连通)

求在原有向图上最多可以添加多少边,使其仍满足不是强连通图
思路:缩点后分成两部分,保证两部分不强连通(两部分之间,其中一部分的入度或出度应为0)

            然后用sum(所有边)-tot(已有边)-两部分点数的乘积。

/*求在原有向图上最多可以添加多少边,使其仍满足不是强连通图
思路:缩点后分成两部分,保证两部分不强连通(两部分之间,其中一部分的入度或出度应为0),
    然后用sum(所有边)-tot(已有边)-两部分点数的乘积
*/
#include 
#include
#include
#include
using namespace std;
#define N 100005
#define maxn 100005
int f[N],ans[N];
struct Edge
{
    int to,next;
}edge[maxn];
int head[N],tot;
int low[N],dfn[N],Stack[N],belong[N];
int inl[N],outl[N];
int index,top,scc;
bool instack[N];
long long int num[N];
void addedge(int u,int v)
{
    edge[tot].to=v;edge[tot].next=head[u];head[u]=tot++;
}
void Tarjan(int u)//tarjan有向图缩点
{
    int v;
    low[u]=dfn[u]=++index;
    Stack[top++]=u;
    instack[u]=true;
    for(int i=head[u];i!=-1;i=edge[i].next){
            v=edge[i].to;
            if(!dfn[v])
            {
                       Tarjan(v);
                       if(low[u]>low[v]) low[u]=low[v];
            }
            else if(instack[v] && low[u]>dfn[v])
            low[u]=dfn[v];
            }
            if(low[u]==dfn[u]){
            scc++;
            do{
            v=Stack[--top];
            instack[v]=false;
            belong[v]=scc;//
            num[scc]++;
               }while(v!=u);
            }
}
void solve(int n)
{
     memset(dfn,0,sizeof(dfn));
     memset(instack,false,sizeof(instack));
     //memset(belong,0,sizeof(belong));
     memset(num,0,sizeof(num));
     index=scc=top=0;
     for(int i=1;i<=n;i++)
     if(!dfn[i]) Tarjan(i);
}
void init(){
     tot=0;
     memset(head,-1,sizeof(head));
     memset(inl,0,sizeof(inl));
     memset(outl,0,sizeof(outl));
}
int main()
{
    int T;
    int n,m,x,y;
    cin>>T;
    for(int t=1;t<=T;t++)
    {
        init();
        scanf("%d %d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d %d",&x,&y);
            addedge(x,y);
        }
        solve(n);
        if(scc==1) printf("Case %d: %d\n",t,-1);
        else{
                //sort(num+1,num+scc+1);
            long long int sum=n*(n-1)-tot;
            long long int ans=0;
            long long int res=0;
            for(int i=1;i<=n;i++)
                for(int j=head[i];j!=-1;j=edge[j].next)
            {
                if(belong[i]!=belong[edge[j].to]) {
                    outl[belong[i]]++;
                    inl[belong[edge[j].to]]++;
                }
            }
            for(int i=scc;i>=1;i--)
                ans+=num[i];
              for(int i=1;i<=scc;i++)
              {
                  if(inl[i]&&outl[i]) continue;
                  res=max(res,sum-(ans-num[i])*num[i]);
              }
                printf("Case %d: %I64d\n",t,res);
        }
    }
    return 0;
}



你可能感兴趣的:(图)