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 */