HDU 4635 Strongly connected(强连通)经典

Strongly connected

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


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
题意:给一个n个点的简单有向图,问最多能加多少条边使得该图仍然是简单有向图,且不是强连通图。简单有向图定义:没有重边,无自环。 强连通图:整个图缩点后就只有一个点,里面包含n个原点,也就是一个连通分量。如果一开始就是一个强连通图,则输出-1。
解题:要加边最多那么加边后的图连通分量越少越好,那么连通分量最少也就是2个。先用n个点构造一个完全图(有向图有:n*(n-1)条边,无向图有:n*(n-1)/2条边),再用构造的边 减去原来有的m条边=ans。再用强连通算法缩点,记录每个新点包含点的个数,从入度为0或出度为0的新点中找出包含点数最小的minnum,再用上面剩余的边ans - minnum*(n-minnum)就是所要的答案。因为如果不减入度为0或出度为0相关的边,那么该点本身包含有入边和出边,加的边永远都是强连通图。所以只能去掉与入度为0或出度为0点的相关边,只减掉一个方向的边,要么全是(n-minnum)点数到minnum点数的入边,那么是minnum点数到(n-minnum)点数的出边。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define ll __int64
const int N = 100005;
struct EDG{
    int to,next;
}edg[N];
int eid,head[N];
int low[N],dfn[N],vist[N],num[N],id[N],deep,stack1[N],tn,top;
int in[N],out[N];

void init(){
    eid=tn=top=deep=0;
    memset(head,-1,sizeof(head));
    memset(vist,0,sizeof(vist));
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    memset(num,0,sizeof(num));
}
void addEdg(int u,int v){
    edg[eid].to=v; edg[eid].next=head[u]; head[u]=eid++;
}
void tarjer(int u){
    stack1[++top]=u;
    vist[u]=1;
    deep++;
    low[u]=dfn[u]=deep;
    for(int i=head[u]; i!=-1; i=edg[i].next){
        int v=edg[i].to;
        if(vist[v]==0){
            vist[v]=1;
            tarjer(v);
            low[u]=min(low[u],low[v]);
        }
        else if(vist[v]==1)
            low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        tn++;
        do{
            vist[stack1[top]]=2;
            num[tn]++;
            id[stack1[top]]=tn;
        }while(stack1[top--]!=u);

    }
}
ll solve(int n,int m){
    ll ans=n*(n-1)-m;
    int minnum=N;
    for(int i=1; i<=n; i++)
        if(vist[i]==0)
         tarjer(i);
    if(tn==1) return -1;
    for(int u=1; u<=n; u++)
    for(int i=head[u]; i!=-1; i=edg[i].next){
        int v=edg[i].to;
        if(id[u]!=id[v])
            in[id[v]]++,out[id[u]]++;
    }
    for(int i=1; i<=tn; i++)
    if(in[i]==0||out[i]==0){
        minnum=min(minnum,num[i]);
    }
    ans-=minnum*(n-minnum);
    
    return ans;
}
int main(){
    int T,n,m,c=0,a,b;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        init();
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d",&a,&b);
            addEdg(a,b);
        }
        printf("Case %d: %I64d\n",++c,solve(n,m));
    }
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值