HDU--Strongly connected--强连通缩点+思维

Strongly connected

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5179    Accepted Submission(s): 2058


 

Problem Description

Give a simple directed graph with N nodes and M edges. Please tell me the maximum number of the edges you can add that the graph is still a simple directed graph. Also, after you add these edges, this graph must NOT be strongly connected.
A simple directed graph is a directed graph having no multiple edges or graph loops.
A strongly connected digraph is a directed graph in which it is possible to reach any node starting from any other node by traversing edges in the direction(s) in which they point.

 

 

Input

The first line of date is an integer T, which is the number of the text cases.
Then T cases follow, each case starts of two numbers N and M, 1<=N<=100000, 1<=M<=100000, representing the number of nodes and the number of edges, then M lines follow. Each line contains two integers x and y, means that there is a edge from x to y.

 

 

Output

For each case, you should output the maximum number of the edges you can add.
If the original graph is strongly connected, just output -1.

 

 

Sample Input

 

3 3 3 1 2 2 3 3 1 3 3 1 2 2 3 1 3 6 6 1 2 2 3 3 1 4 5 5 6 6 4

 

 

Sample Output

 

Case 1: -1 Case 2: 1 Case 3: 15

 

 

Source

2013 Multi-University Training Contest 4

给出一个有向图,问是否强连通,强连通输出-1,否则求加最多的边,无重复边和自环,使得其还是不强连通。

假设我们现在进行缩点之后得到一些强连通块,将点数最少的X块单独拿出来,其他的合并为Y块。

那么此时可以有X*(X-1) X块强连通最多边+Y*(Y-1) Y块强连通最多边+X*Y X的每一个点向Y连一条边。此时是不是强连通的最多边,然后减去已经有的M,即为所求。

X*(X-1)+Y*(Y-1)-X*Y-M=N*N-N-X*Y-M 。所以要求X*Y最小值,X+Y=N,那么X 与 Y相差最大时符合条件。所以选择一个入度或出度等于0的且点最少的那个强连通块作为X。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<queue>
#define ll long long
using namespace std;
int dx[2]= {0,1};
int dy[2]= {1,0};
const int INF=99999999;
const int MAXN = 100000+66;
const int MAXM = 100000+66;
struct Edge
{
    int from,to,next;
} e[MAXM];
int dfn[MAXN],low[MAXN],head[MAXN],link[MAXN],visx,tot,tot_edge;
int n,nn,m,cnt,belong[MAXN],in[MAXN],out[MAXN],a[MAXN],sum[MAXN];
bool exist[MAXN];
void PrePare()
{
    cnt=0;
    visx=0;
    tot=0;
    memset(dfn,-1,sizeof dfn );
    memset(low,-1,sizeof low );
    memset(head,0,sizeof head );
    memset(link,0,sizeof link );
    memset(belong,0,sizeof belong );
    memset(exist,0,sizeof exist );
    memset(sum,0,sizeof sum );
    memset(in,0,sizeof in );
    memset(out,0,sizeof out );
}
void Add_Edge(int u,int v,int *head)
{
    e[++tot].to=v;
    e[tot].from=u;
    e[tot].next=head[u];
    head[u]=tot;
}
stack<int> st;
void Tarjan(int u)
{
    dfn[u]=low[u]= ++visx;
    st.push(u);
    exist[u]=true;
    for(int i=head[u]; i; i=e[i].next)
    {
        int v=e[i].to;
        if(dfn[v]==-1)
        {
            Tarjan(v);
            low[u]=min(low[v],low[u]);
        }
        else if(exist[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        ++cnt;//强连通点的个数
        while(1)
        {
            int v=st.top();
            st.pop();
            exist[v]=0;
            belong[v]=cnt;//v这个
            //sum[cnt]+=a[v];//看这个缩点的权值
            if(v==u)
                break;
        }
    }
}
void new_Map()
{
    for(int i=1; i<=n; i++)
    {
        sum[belong[i]]++;
        for(int j=head[i]; j; j=e[j].next)
        {
            int v=e[j].to;
            if(belong[i]!=belong[v])
            {
                in[belong[v]]++;
                out[belong[i]]++;
            }
        }
    }
}
ll solve()
{
    if(cnt==1)
    {
        return -1;
    }
    else
    {
        new_Map();
        int ans=0;
        //
        int left=100000+1;
        for(int i=1; i<=cnt; i++)
        {
            if(in[i]==0||out[i]==0)
            {
                if(sum[i]<left)
                {
                    left=sum[i];
                }
            }
        }
        return (ll)(n*n-n-left*(n-left)-m);
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    int num=0;
    while(t--)
    {
        scanf("%d%d",&n,&m);
        nn=n;
        PrePare();
        for(int i=1; i<=m; i++)
        {
            int u,v;
            scanf("%d %d",&u,&v);
            Add_Edge(u,v,head);
        }
        for(int i=1; i<=n; i++)
            if(dfn[i]==-1)
                Tarjan(i);//缩点
        printf("Case %d: %lld\n",++num,solve());
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值