HDU 4635 —— Strongly connected——————【 强连通、最多加多少边仍不强连通】

Strongly connected

Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

Submit Status Practice HDU 4635

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

题目大意:给n个结点,m条有向边。问你最多加多少条边,让原图仍然不是强连通的。如果图本身就是强连通的,输出-1

解题思路:如果要让图不是强连通图,那么必须会将分成两部分。我们设左部分为X,右部分为Y。X这边的结点个数设为x,X这边的结点个数设为y,想要加边最多,那么可以让左边X成为完全图,右边Y成为完全图。让X与Y之间全部都是一个方向的边,即如果是X--->Y的,那么所有都是从X->Y的;如果是从Y--->X的,那么所有都是Y->X的。那么我们可以得到一个公式计算这样能形成的所有边数  F = x*y + x*(x-1) + y*(y-1)表示X与Y之间形成的边数+X形成完全图的边数+Y形成完全图的边数。x+y = n。公式可以进一步化简得:F = n*n - n - (xy)。这是总的边数。那么如果想让F越大,那么只要x*y值越小即可。当x+y 为定值时,x*y的值越小,则需要x与y的差值越大。那么我们通过缩点以后,让缩点出度或者入度为0的单独放在X或者Y,让剩余的放到另一侧。然后通过枚举这样的缩点,即可找到结果。

#include<stdio.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<string.h>
#include<vector>
using namespace std;
typedef long long INT;
const int maxn = 100100;
struct Edge{
    int from,to,dist,next;
    Edge(){}
    Edge(int _to,int _next):to(_to),next(_next){}
}edges[maxn];
int tot, head[maxn];
void init(){
    tot = 0;
    memset(head,-1,sizeof(head));
}
void AddEdge(int _u,int _v){
    edges[tot] = Edge(_v,head[_u]);
    head[_u] = tot++;
}
int dfs_clock, scc_cnt;
int sccno[maxn], dfn[maxn], lowlink[maxn];
stack<int>S;
void dfs(int u){
    lowlink[u] = dfn[u] = ++dfs_clock;
    S.push(u);
    for(int i = head[u]; i != -1; i = edges[i].next){
        int v = edges[i].to;
        if(!dfn[v]){
            dfs(v);
            lowlink[u] = min(lowlink[u], lowlink[v]);
        }else if(!sccno[v]){
            lowlink[u] = min(lowlink[u],dfn[v]);
        }
    }
    if(lowlink[u] == dfn[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(dfn,0,sizeof(dfn));
    for(int i = 1; i <= n; i++){
        if(!dfn[i]){
            dfs(i);
        }
    }
}
int outdeg[maxn], indeg[maxn];
INT sccsz[maxn];
int main(){
    int T, m, cas = 0;
    INT n;
    scanf("%d",&T);
    while(T--){
        scanf("%lld%d",&n,&m);
        init();
        int a,b;
        for(int i = 0; i < m; i++){
            scanf("%d%d",&a,&b);
            AddEdge(a,b);
        }
        find_scc(n);
        printf("Case %d: ",++cas);
        if(scc_cnt == 1){
            puts("-1");continue;
        }
        memset(indeg,0,sizeof(indeg));
        memset(outdeg,0,sizeof(outdeg));
        memset(sccsz,0,sizeof(sccsz));
        for(int i = 1; i <= n; i++){
            sccsz[sccno[i]]++;
            for(int j = head[i]; j != -1; j = edges[j].next){
                int v = edges[j].to;
                if(sccno[i] == sccno[v]){
                    continue;
                }
                indeg[sccno[v]]++;
                outdeg[sccno[i]]++;
            }
        }
        INT ans = 0;
        for(int i = 1; i <= scc_cnt; i++){
            if(indeg[i] == 0 ||outdeg[i] == 0){
                ans = max( ans, (n*n - n - sccsz[i]*(n - sccsz[i]))-m );
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

/*
555
7 9
1 5
1 2
5 6
6 7
7 5
6 4
2 4
4 3
3 2

*/

  

时间: 2024-10-11 17:13:39

HDU 4635 —— Strongly connected——————【 强连通、最多加多少边仍不强连通】的相关文章

[tarjan] hdu 4635 Strongly connected

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4635 Strongly connected Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1568    Accepted Submission(s): 654 Problem Description Give a simple dir

HDU 4635 Strongly connected (有向图的强连通分量)

Strongly connected Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) 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 grap

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

HDU 4635 Strongly connected(强连通分量缩点+数学思想)

题意:给出一个图,如果这个图一开始就不是强连通图,求出最多加多少条边使这个图还能保持非强连通图的性质. 思路:不难想到缩点转化为完全图,然后找把它变成非强连通图需要去掉多少条边,但是应该怎么处理呢……有人给出这样的答案,找到分量中点数最少的块,把它的所有入边都去掉……好像是对的,但是万一这个块本来就有一个入度怎么办?这个边是不可以删的啊.所以我觉得这种办法是有点的问题的,所以最靠谱的方法还是斌哥他们给出的方法,最后的时候把点分成两个集合x和y,x和y本身都是完全图块,然后让x中的每一个点都指向y

HDU 4635 Strongly connected(强连通分量,变形)

题意:给出一个有向图(不一定连通),问最多可添加多少条边而该图仍然没有强连通. 思路: 强连通分量必须先求出,每个强连通分量包含有几个点也需要知道,每个点只会属于1个强连通分量. 在使图不强连通的前提下,要添加尽可能多的边.边至多有n*(n-1)条,而已经给了m条,那么所能添加的边数不可能超过k=n*(n-1)-m. 这k条边还有部分不能添加,一添加立刻就强连通.一个强连通图最少只需要n条边,根据强连通的特性,缩点之后必定是不会有环的存在的,那么只要继续保持没有环的存在即可.我们只要让其中1个强

HDU 4635 Strongly connected 强连通分量

参考:http://www.cnblogs.com/jackge/p/3231767.html 讲的很好 感悟:最好的情况肯定是完全图,但是不允许,所以一定是有些符合u->v,但是v不能到u, 在保证这样的情况,最大化边数,最终会形成两个图,然后应用不等式 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath>

hdu 4635 Strongly connected (tarjan)

题意:给一个n个顶点m条弧的简单有向图(无环无重边),求最多能够加入多少条弧使得加入后的有向图仍为简单有向图且不是一个强连通图.假设给的简单有向图本来就是强连通图,那么输出-1. 分析: 1.用tarjan算法求出强连通分量的个数,假设个数为1,那么输出-1,结束,否则运行2 2.如果将一些强连通分量合并为有n1个顶点简单全然图1,而将剩下的强连通分量合并为n2个顶点的简单全然图2,跨这两个简单全然图的弧的方向仅仅能是单向的,如果m1为全然图1内部的弧的数量,m2为为全然图2内部的弧的数量.m3

Hdu 4635 Strongly connected

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4635 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 7 typedef long long LL; 8 const int maxn = 100005; 9 const int INF

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

这道题其实做完之后发现几乎就是模板题,然而之前有个地方想了一周一直拧不过来,题目是最多加多少条边仍然不是强连通图,也就可以理解为再多加一条边就无论如何都是强连通图,等价于最多去掉几条边使之仍未强连通图,当此时再多去一条边的时候,等价于最少去掉几条变使原图不强连通,好了终于绕完了,都给我自己绕蒙了,那么我们是最少去掉多少条边使原图不强联通,我们先把它变成一个完全图,然后再减去题目中给的边 ans=n*(n-1)-m-x,至于这个x是多少呢,就是我最少要去掉的边数,因为x=(n-a)*a,n是一定的