hdu4635Strongly connected 【求最多加多少边仍不是强连通分量】

这道题其实做完之后发现几乎就是模板题,然而之前有个地方想了一周一直拧不过来,题目是最多加多少条边仍然不是强连通图,也就可以理解为再多加一条边就无论如何都是强连通图,等价于最多去掉几条边使之仍未强连通图,当此时再多去一条边的时候,等价于最少去掉几条变使原图不强连通,好了终于绕完了,都给我自己绕蒙了,那么我们是最少去掉多少条边使原图不强联通,我们先把它变成一个完全图,然后再减去题目中给的边
ans=n*(n-1)-m-x,至于这个x是多少呢,就是我最少要去掉的边数,因为x=(n-a)*a,n是一定的a和(n-a)差越大,二者乘积就越小,ans就越大,所以我们要做的就是把那些缩点分成两个集合,一个集合里是所有缩点中点的个数最小的集合,其他的缩点放在另一个集合里,并且那个单独在一个集合的缩点,一定要满足入度或出度为0,因为只有这样才能保证这个边是只有一个方向的,也就是没有环,不是强连通的
还有就是判-1,只用团的个数,最终结果可能等于0!

#include <iostream>
#include <vector>
#include <stdio.h>
#include <string.h>
#include <stack>
using namespace std;
const int maxn=200005;
vector <int>G[maxn];
int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt;
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++;
        for(;;)
        {
            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=0; i<n; i++)if(!pre[i])dfs(i);
}

int in0[maxn],out0[maxn];
int main()
{
    int T,n,m,cas=1;
    int num[maxn];
    scanf("%d",&T);
    while(T--)
    {
        memset(in0,0,sizeof(in0));
        memset(out0,0,sizeof(out0));
        memset(num,0,sizeof(num));
        scanf("%d%d",&n,&m);
        for(int i=0; i<n; i++)
            G[i].clear();
        for(int i=0; i<m; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            u--;
            v--;
            G[u].push_back(v);
        }
        find_scc(n);
        for(int i=1; i<=scc_cnt; i++)
            in0[i]=out0[i]=1;
        for(int u=0; u<n; u++)
        {
            for(int i=0; i<G[u].size(); i++)
            {
                int v=G[u][i];
                if(sccno[u]!=sccno[v])
                    in0[sccno[v]]=out0[sccno[u]]=0;
            }
            num[sccno[u]]++;
        }
        int maxnum=maxn;
        for(int  i=1; i<=scc_cnt; i++)
        {
            if(in0[i]==1||out0[i]==1)
            {
                if(num[i]<maxnum)
                    maxnum=num[i];
            }
        }
        //cout<<maxnum<<endl;
        long long ans=n*(n-1)-m-(n-maxnum)*maxnum;
        if(scc_cnt!=1) printf("Case %d: %lld\n",cas++,ans);
        else printf("Case %d: -1\n",cas++);


    }
    return 0;
}

你可能感兴趣的:(图论,连通)