Strongly connected HDU - 4635 加最多的边让其保持不强连通

题目链接:https://vjudge.net/problem/HDU-4635#author=0
转自:https://xiaoxiaoh.blog.csdn.net/article/details/104441555
题意:给一个有向无重边无自环的图,求最多可以添加多少边,让其仍然不连通,没有重边且没有自环。
思路:一个n个点的有向完全图的边数为n* (n-1),已经有了m条边,剩余n* (n-1)-m条边,由于最后的图不能是强连通,要减去包括点数目最少的强连通分量s的出边或入边才能保证添加边尽可能多的同时图不强连通,结果为n* (n-1)-m-minn* (n-minn)。同时要保证找到的s的入度或出度为0,否则无论怎么加边,s与合并后的连通分量是强连通的。当s入度为0,减去的是s的入边,反之减去的是出边。

#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#include <cstring>
#include <iostream>
#include <cmath>
#include <set>
#include <fstream>
#include <list>
#include <stack>
#include <map>
using namespace std;
const int maxn=1e5+5;
vector <int> g[maxn];
vector <pair<int,int> >edge;
int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt,cntD[maxn];
int in[maxn],out[maxn];
stack<int> s;
void dfs(int u)
{
    pre[u]=lowlink[u]=++dfs_clock;
    s.push(u);
    for(int i=0; i<g[u].size(); i++)
    {
        int v=g[u][i];
        if(!pre[v])
        {
            dfs(v);
            lowlink[u]=min(lowlink[u],lowlink[v]);
        }
        else if(!sccno[v])
        {
            lowlink[u]=min(lowlink[u],pre[v]);
        }
    }
    if(lowlink[u]==pre[u])
    {
        scc_cnt++;
        while(1)
        {
            int x=s.top();
            s.pop();
            sccno[x]=scc_cnt;
            if(x==u)
                break;
        }
    }
}
void find_scc(int n)
{
    dfs_clock=scc_cnt=0;
    memset(sccno,0,sizeof(sccno));
    memset(pre,0,sizeof(pre));
    for(int i=1; i<=n; i++)
    {
        if(!pre[i])
            dfs(i);
    }
}
int main()
{
    int T,kase=1;
    scanf("%d",&T);
    while(T--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        edge.clear();
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        memset(cntD,0,sizeof(cntD));
        for(int i=0; i<=n; i++)
        {
            g[i].clear();
        }
        for(int i=0; i<m; i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            g[x].push_back(y);
            edge.push_back(make_pair(x,y));
        }
        find_scc(n);
        printf("Case %d: ",kase++);
        if(scc_cnt==1)
        {
            printf("-1\n");
            continue;
        }
        for(int i=0; i<m; i++)
        {
            int u=edge[i].first,v=edge[i].second;
            if(sccno[u]!=sccno[v])
            {
                in[sccno[v]]++;
                out[sccno[u]]++;
            }
        }
        for(int i=1;i<=n;i++)
        {
            cntD[sccno[i]]++;
        }
        int minn=1e9;
        for(int i=1; i<=scc_cnt; i++)
        {
            if(!in[i]||!out[i])
            {
                minn=min(minn,cntD[i]);
            }
        }
        long long ans=(long long ) n*(n-1);
        ans-=m;
        ans=ans-(long long )minn*(n-minn);
        printf("%lld\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值