HDU-4635-Strongly connected(强连通分量)

本文介绍了一种求解如何通过增加最少数量的边使给定图变为最大不连通图的方法。通过Tarjan算法进行强连通分量的划分,并计算在保持不连通性的前提下所需的边数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4635


题意:问当前图加多少边成为最大不连通图。

题解:N个点,M条边,

    当前图的最大不连通图即为加边后缩点为X,Y两个部分,

    有X->Y或者Y->X的完全边且XY都为完全图;

    则最大不连通图边数 F=x*y+x*(x-1)+y*(y-1)即 F=N*N-N-x*y

 由于x+y=N,显然我们要使得abs(x-y)最大,这样直接选择缩点后入度或出度为0的且点最少的一个缩点为X。

    答案显然是ans=max(ans,sum[i]*(sum[i]-1)+(n-sum[i])*(n-sum[i]-1)+sum[i]*(n-sum[i])-m);


#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1e3+7;
const int MAXM = 1e6+7;
struct node
{
    int v,next;
} edge[MAXM];
int index,head[MAXM];
void add_edge(int u,int v)
{
    edge[index].v=v;
    edge[index].next=head[u];
    head[u]=index++;
}
int low[MAXN],stack_[MAXN],belong[MAXN],DFN[MAXN],sum[MAXN];
bool in_stack[MAXN];
int top,temp,poi,cir;
void Tarjan(int u)
{
    int p;
    DFN[u]=low[u]=++temp;
    in_stack[u]=1;
    stack_[top++]=u;
    for(int i=head[u]; i+1; i=edge[i].next)
    {
        int v=edge[i].v;
        if(!DFN[v])
        {
            Tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(in_stack[v])
            low[u]=min(low[u],DFN[v]);
    }
    if(DFN[u]==low[u])
    {
        cir++;
        do
        {
            p=stack_[--top];
            in_stack[p]=0;
            belong[p]=cir;
            sum[cir]++;
        }
        while(p!=u);
    }
}
int in[MAXN],out[MAXN];
void init()
{
    index=cir=top=temp=0;
    memset(head,-1,sizeof(head));
    memset(sum,0,sizeof(sum));
    memset(DFN,0,sizeof(DFN));
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
}
int main()
{
    int T,n,m;
    scanf("%d",&T);
    int cas=0;
    while(T--)
    {
        int a,b;
        init();
        scanf("%d%d",&n,&m);
        for(int i=0; i<m; ++i)
        {
            scanf("%d%d",&a,&b);
            add_edge(a,b);
        }
        for(int i=1; i<=n; ++i)
            if(!DFN[i])Tarjan(i);
        if(cir<=1){printf("Case %d: -1\n",++cas);continue;}
        for(int i=1; i<=n; ++i)
            for(int j=head[i]; j+1; j=edge[j].next)
            {
                int v=edge[j].v;
                if(belong[i]!=belong[v])
                {
                    out[belong[i]]++;
                    in[belong[v]]++;
                }
            }
        int ans=0;

        for(int i=1; i<=cir; ++i)
            if(!out[i]||!in[i])
            {
                ans=max(ans,sum[i]*(sum[i]-1)+(n-sum[i])*(n-sum[i]-1)+sum[i]*(n-sum[i])-m);
            }
        printf("Case %d: %d\n",++cas,ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值